blob: 740210c6feddc811753148d4171b702f2ff4d90b [file] [log] [blame]
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001/* saa711x - Philips SAA711x video decoder driver
2 * This driver can work with saa7111, saa7111a, saa7113, saa7114,
3 * saa7115 and saa7118.
Hans Verkuile19b2fc2005-11-13 16:08:04 -08004 *
5 * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
6 * the saa7111 driver by Dave Perks.
7 *
8 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
9 * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
10 *
11 * Slight changes for video timing and attachment output by
12 * Wolfgang Scherr <scherr@net4you.net>
13 *
14 * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
15 * by Ronald Bultje <rbultje@ronald.bitfreak.net>
16 *
17 * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
18 * (2/17/2003)
19 *
20 * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030021 *
22 * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
23 * SAA7111, SAA7113 and SAA7118 support
Hans Verkuile19b2fc2005-11-13 16:08:04 -080024 *
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * as published by the Free Software Foundation; either version 2
28 * of the License, or (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 */
39
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -030040#include "saa711x_regs.h"
Hans Verkuile19b2fc2005-11-13 16:08:04 -080041
42#include <linux/kernel.h>
43#include <linux/module.h>
44#include <linux/slab.h>
45#include <linux/i2c.h>
46#include <linux/videodev2.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080047#include <media/v4l2-common.h>
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -030048#include <media/saa7115.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020049#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080050
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030051MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030052MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
53 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080054MODULE_LICENSE("GPL");
55
56static int debug = 0;
Hans Verkuilfac9e892006-01-09 15:32:40 -020057module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080058
59MODULE_PARM_DESC(debug, "Debug level (0-1)");
60
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030061static unsigned short normal_i2c[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030062 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
63 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030064 I2C_CLIENT_END };
Hans Verkuile19b2fc2005-11-13 16:08:04 -080065
66
67I2C_CLIENT_INSMOD;
68
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030069struct saa711x_state {
Hans Verkuile19b2fc2005-11-13 16:08:04 -080070 v4l2_std_id std;
71 int input;
72 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020073 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080074 int bright;
75 int contrast;
76 int hue;
77 int sat;
78 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020079 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030080 u32 crystal_freq;
81 u8 ucgc;
82 u8 cgcdiv;
83 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080084};
85
86/* ----------------------------------------------------------------------- */
87
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030088static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080089{
90 return i2c_smbus_write_byte_data(client, reg, value);
91}
92
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030093/* Sanity routine to check if a register is present */
94static 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
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300130static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800131{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300132 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800133 unsigned char reg, data;
134
135 while (*regs != 0x00) {
136 reg = *(regs++);
137 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300138
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)) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300142 if (saa711x_write(client, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300143 return -1;
144 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800145 }
146 return 0;
147}
148
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300149static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800150{
151 return i2c_smbus_read_byte_data(client, reg);
152}
153
154/* ----------------------------------------------------------------------- */
155
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300156/* SAA7111 initialization table */
157static 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 */
197static 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
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800225/* If a value differs from the Hauppauge driver values, then the comment starts with
226 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
227 Hauppauge driver sets. */
228
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300229/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800230static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300231 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300232 R_01_INC_DELAY, 0x48, /* white peak control disabled */
233 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
234 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
235 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300236 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300237 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
238 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
239 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
240 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
241 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
242 R_0D_CHROMA_HUE_CNTL, 0x00,
243 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
244 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
245 R_11_MODE_DELAY_CNTL, 0x00,
246 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
247 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
248 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
249 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
250 R_19_RAW_DATA_OFF_CNTL, 0x80,
251 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
252 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
253 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
254 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300255
256 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300257 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
258 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800259 0x00, 0x00
260};
261
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300262/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800263static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300264 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
265 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
266 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
267 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800268 0x00, 0x00
269};
270
271/* ============== SAA7715 VIDEO templates ============= */
272
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300273/* Used on saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800274static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300275 /* hsize = 0x2d0 = 720 */
276 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
277 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800278
279 /* Why not in 60hz-Land, too? */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300280 R_D0_B_HORIZ_PRESCALING, 0x01, /* downscale = 1 */
281 /* hor lum scaling 0x0400 = 1 */
282 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
283 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
284
285 /* must be hor lum scaling / 2 */
286 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
287 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800288
289 0x00, 0x00
290};
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300291
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300292/* Used on saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800293static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300294 /* output window size = 248 (but 60hz is 240?) */
295 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8,
296 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800297
298 /* Why not in 60hz-Land, too? */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300299 R_D5_B_LUMA_CONTRAST_CNTL, 0x40, /* Lum contrast, nominal value = 0x40 */
300 R_D6_B_CHROMA_SATURATION_CNTL, 0x40, /* Chroma satur. nominal value = 0x80 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800301
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300302 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
303 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
304
305 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
306 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800307
308 0x00, 0x00
309};
310
311static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300312 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
313 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800314
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300315 R_15_VGATE_START_FID_CHG, 0x03,
316 R_16_VGATE_STOP, 0x11,
317 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800318
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300319 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
320 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800321
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300322 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800323
324 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300325 R_90_A_TASK_HANDLING_CNTL, 0x80,
326 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
327 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
328 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
329
330 /* hoffset low (input), 0x0002 is minimum */
331 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
332 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
333
334 /* hsize low (input), 0x02d0 = 720 */
335 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
336 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
337
338 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
339 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
340
341 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
342 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
343
344 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
345 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
346
347 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
348 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800349
350 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300351 R_C0_B_TASK_HANDLING_CNTL, 0x00,
352 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
353 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
354 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800355
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300356 /* 0x0002 is minimum */
357 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
358 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800359
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300360 /* 0x02d0 = 720 */
361 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
362 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
363
364 /* vwindow start 0x12 = 18 */
365 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
366 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
367
368 /* vwindow length 0xf8 = 248 */
369 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0xf8,
370 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
371
372 /* hwindow 0x02d0 = 720 */
373 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
374 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
375
376 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
377 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
378 R_F5_PULSGEN_LINE_LENGTH, 0xad,
379 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
380
381 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
382 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
383 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
384 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
385 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800386 0x00, 0x00
387};
388
389static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300390 /* hsize low (output), 720 same as 60hz */
391 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
392 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800393
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300394 R_D0_B_HORIZ_PRESCALING, 0x01, /* down scale = 1 */
395 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00, /* hor lum scaling 0x0400 = 1 */
396 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
397
398 /* must be hor lum scaling / 2 */
399 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
400 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800401
402 0x00, 0x00
403};
404static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300405 /* vsize low (output), 0x0120 = 288 */
406 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
407 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800408
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300409 R_D5_B_LUMA_CONTRAST_CNTL, 0x40, /* Lum contrast, nominal value = 0x40 */
410 R_D6_B_CHROMA_SATURATION_CNTL, 0x40, /* Chroma satur. nominal value = 0x80 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800411
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300412 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
413 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
414
415 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
416 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800417
418 0x00, 0x00
419};
420
421static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300422 R_80_GLOBAL_CNTL_1, 0x00,
423 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800424
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300425 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
426 R_16_VGATE_STOP, 0x16,
427 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800428
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300429 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
430 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800431
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300432 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800433
434 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300435 R_90_A_TASK_HANDLING_CNTL, 0x81,
436 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
437 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
438 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
439
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800440 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
441 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300442 /* hoffset low (input), 0x0002 is minimum */
443 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
444 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
445
446 /* hsize low (input), 0x02d0 = 720 */
447 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
448 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
449
450 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
451 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
452
453 /* vsize 0x12 = 18 */
454 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
455 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
456
457 /* hsize 0x05a0 = 1440 */
458 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
459 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
460 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
461 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800462
463 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300464 R_C0_B_TASK_HANDLING_CNTL, 0x00,
465 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
466 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
467 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800468
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300469 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
470 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
471 /* hoffset low (input), 0x0002 is minimum. See comment above. */
472 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
473 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800474
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300475 /* hsize 0x02d0 = 720 */
476 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
477 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
478
479 /* voffset 0x16 = 22 */
480 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
481 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
482
483 /* vsize 0x0120 = 288 */
484 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
485 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
486
487 /* hsize 0x02d0 = 720 */
488 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
489 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
490
491 /* vsize 0x0120 = 288 */
492 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
493 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
494
495 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
496 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
497 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
498 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
499
500 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
501 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler (was 0xD0) */
502 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
503 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
504 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
505
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800506 0x00, 0x00
507};
508
509/* ============== SAA7715 VIDEO templates (end) ======= */
510
511static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300512 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
513 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
514 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
515 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
516 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
517
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800518 0x00, 0x00
519};
520
521static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300522 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
523 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
524 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
525 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
526 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
527
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800528 0x00, 0x00
529};
530
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300531
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800532static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300533 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
534 0x82, 0x00, /* Reserved register - value should be zero*/
535 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
536 R_84_I_PORT_SIGNAL_DEF, 0x20,
537 R_85_I_PORT_SIGNAL_POLAR, 0x21,
538 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
539 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800540
541 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300542 R_A0_A_HORIZ_PRESCALING, 0x01,
543 R_A1_A_ACCUMULATION_LENGTH, 0x00,
544 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800545
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300546 /* Configure controls at nominal value*/
547 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
548 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
549 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
550
551 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
552 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
553 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
554
555 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
556
557 /* must be horiz lum scaling / 2 */
558 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
559 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
560
561 /* must be offset luma / 2 */
562 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
563
564 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
565 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
566
567 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
568 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
569
570 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
571
572 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
573 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
574 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
575 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
576
577 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
578 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
579 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
580 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800581
582 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300583 R_D0_B_HORIZ_PRESCALING, 0x01,
584 R_D1_B_ACCUMULATION_LENGTH, 0x00,
585 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800586
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300587 /* Configure controls at nominal value*/
588 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
589 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
590 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800591
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300592 /* hor lum scaling 0x0400 = 1 */
593 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
594 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
595
596 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
597
598 /* must be hor lum scaling / 2 */
599 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
600 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
601
602 /* must be offset luma / 2 */
603 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
604
605 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
606 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
607
608 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
609 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
610
611 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
612
613 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
614 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
615 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
616 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
617
618 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
619 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
620 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
621 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
622
623 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
624 R_F3_PLL_INCREMENT, 0x46,
625 R_F4_PLL2_STATUS, 0x00,
626 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
627 R_F8_PULSE_B_POS, 0x00,
628 R_F9_PULSE_B_POS_MSB, 0x4b,
629 R_FA_PULSE_C_POS, 0x00,
630 R_FB_PULSE_C_POS_MSB, 0x4b,
631
632 /* PLL2 lock detection settings: 71 lines 50% phase error */
633 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800634
635 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300636 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
637 R_41_LCR_BASE, 0xff,
638 R_41_LCR_BASE+1, 0xff,
639 R_41_LCR_BASE+2, 0xff,
640 R_41_LCR_BASE+3, 0xff,
641 R_41_LCR_BASE+4, 0xff,
642 R_41_LCR_BASE+5, 0xff,
643 R_41_LCR_BASE+6, 0xff,
644 R_41_LCR_BASE+7, 0xff,
645 R_41_LCR_BASE+8, 0xff,
646 R_41_LCR_BASE+9, 0xff,
647 R_41_LCR_BASE+10, 0xff,
648 R_41_LCR_BASE+11, 0xff,
649 R_41_LCR_BASE+12, 0xff,
650 R_41_LCR_BASE+13, 0xff,
651 R_41_LCR_BASE+14, 0xff,
652 R_41_LCR_BASE+15, 0xff,
653 R_41_LCR_BASE+16, 0xff,
654 R_41_LCR_BASE+17, 0xff,
655 R_41_LCR_BASE+18, 0xff,
656 R_41_LCR_BASE+19, 0xff,
657 R_41_LCR_BASE+20, 0xff,
658 R_41_LCR_BASE+21, 0xff,
659 R_41_LCR_BASE+22, 0xff,
660 R_58_PROGRAM_FRAMING_CODE, 0x40,
661 R_59_H_OFF_FOR_SLICER, 0x47,
662 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
663 R_5D_DID, 0xbd,
664 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800665
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300666 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
667 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800668
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300669 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
670 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
671 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800672 0x00, 0x00
673};
674
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300675static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800676{
677 c ^= (c >> 4);
678 c ^= (c >> 2);
679 c ^= (c >> 1);
680
681 return c & 1;
682}
683
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300684static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800685{
686 static const u8 biphase_tbl[] = {
687 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
688 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
689 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
690 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
691 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
692 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
693 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
694 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
695 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
696 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
697 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
698 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
699 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
700 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
701 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
702 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
703 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
704 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
705 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
706 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
707 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
708 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
709 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
710 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
711 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
712 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
713 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
714 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
715 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
716 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
717 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
718 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
719 };
720 int i;
721 u8 c, err = 0;
722
723 for (i = 0; i < 2 * 13; i += 2) {
724 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
725 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
726 dst[i / 2] = c;
727 }
728 return err & 0xf0;
729}
730
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300731static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800732{
733 static const int wss_bits[8] = {
734 0, 0, 0, 1, 0, 1, 1, 1
735 };
736 unsigned char parity;
737 int wss = 0;
738 int i;
739
740 for (i = 0; i < 16; i++) {
741 int b1 = wss_bits[p[i] & 7];
742 int b2 = wss_bits[(p[i] >> 3) & 7];
743
744 if (b1 == b2)
745 return -1;
746 wss |= b2 << i;
747 }
748 parity = wss & 15;
749 parity ^= parity >> 2;
750 parity ^= parity >> 1;
751
752 if (!(parity & 1))
753 return -1;
754
755 return wss;
756}
757
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300758static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800759{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300760 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200761 u32 acpf;
762 u32 acni;
763 u32 hz;
764 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300765 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800766
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300767 /* 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
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200771 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200772
773 /* sanity check */
774 if (freq < 32000 || freq > 48000)
775 return -EINVAL;
776
777 /* hz is the refresh rate times 100 */
778 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
779 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
780 acpf = (25600 * freq) / hz;
781 /* acni = (256 * freq * 2^23) / crystal_frequency =
782 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300783 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200784 f = freq;
785 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300786 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200787 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300788 if (state->ucgc) {
789 acpf = acpf * state->cgcdiv / 16;
790 acni = acni * state->cgcdiv / 16;
791 acc = 0x80;
792 if (state->cgcdiv == 3)
793 acc |= 0x40;
794 }
795 if (state->apll)
796 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200797
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300798 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
799 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
800 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300801
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300802 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
803 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300804 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300805 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300806 (acpf >> 16) & 0x03);
807
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300808 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
809 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
810 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800811 state->audclk_freq = freq;
812 return 0;
813}
814
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300815static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800816{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300817 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800818
819 switch (ctrl->id) {
820 case V4L2_CID_BRIGHTNESS:
821 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200822 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800823 return -ERANGE;
824 }
825
826 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300827 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800828 break;
829
830 case V4L2_CID_CONTRAST:
831 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200832 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800833 return -ERANGE;
834 }
835
836 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300837 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800838 break;
839
840 case V4L2_CID_SATURATION:
841 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200842 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800843 return -ERANGE;
844 }
845
846 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300847 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800848 break;
849
850 case V4L2_CID_HUE:
851 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200852 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800853 return -ERANGE;
854 }
855
856 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300857 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800858 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200859
860 default:
861 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800862 }
863
864 return 0;
865}
866
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300867static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800868{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300869 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800870
871 switch (ctrl->id) {
872 case V4L2_CID_BRIGHTNESS:
873 ctrl->value = state->bright;
874 break;
875 case V4L2_CID_CONTRAST:
876 ctrl->value = state->contrast;
877 break;
878 case V4L2_CID_SATURATION:
879 ctrl->value = state->sat;
880 break;
881 case V4L2_CID_HUE:
882 ctrl->value = state->hue;
883 break;
884 default:
885 return -EINVAL;
886 }
887
888 return 0;
889}
890
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300891static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800892{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300893 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800894
Hans Verkuil30b54d52006-01-09 15:25:43 -0200895 /* Prevent unnecessary standard changes. During a standard
896 change the I-Port is temporarily disabled. Any devices
897 reading from that port can get confused.
898 Note that VIDIOC_S_STD is also used to switch from
899 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
900 all I2C devices then you do not want to have an unwanted
901 side-effect here. */
902 if (std == state->std)
903 return;
904
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800905 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
906 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200907 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300908 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800909 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200910 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300911 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800912 }
913
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300914 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300915 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300916 50 Hz / 625 lines 60 Hz / 525 lines
917 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
918 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
919 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
920 011 NTSC N (3.58MHz) PAL M (3.58MHz)
921 100 reserved NTSC-Japan (3.58MHz)
922 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300923 if (state->ident == V4L2_IDENT_SAA7111 ||
924 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300925 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300926
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300927 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300928 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300929 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300930 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300931 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300932 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300933 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300934 reg |= 0x40;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300935 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300936 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300937 } else {
938 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300939 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300940
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300941 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300942 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300943 }
944
945 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300946 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300947 }
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300948
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800949 state->std = std;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800950}
951
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300952static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800953{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300954 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800955
956 return state->std;
957}
958
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300959static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800960{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300961 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800962 int reg1e, reg1f;
963 int signalOk;
964 int vcr;
965
Hans Verkuilfac9e892006-01-09 15:32:40 -0200966 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300967 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800968 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300969 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800970 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200971 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
972 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800973 return;
974 }
975
976 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300977 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
978 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800979
980 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
981 vcr = !(reg1f & 0x10);
982
Hans Verkuil21fa7152006-01-09 15:25:41 -0200983 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200984 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200985 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200986 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200987 }
Hans Verkuilfac9e892006-01-09 15:32:40 -0200988 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
989 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800990
991 switch (reg1e & 0x03) {
992 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200993 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800994 break;
995 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200996 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800997 break;
998 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200999 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001000 break;
1001 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001002 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001003 break;
1004 }
1005}
1006
1007/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001008static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001009{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001010 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001011 int is_50hz = (state->std & V4L2_STD_625_50);
1012 u8 lcr[24];
1013 int i, x;
1014
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001015#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 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001022 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001023 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001024#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001025
1026 for (i = 0; i <= 23; i++)
1027 lcr[i] = 0xff;
1028
1029 if (fmt->service_set == 0) {
1030 /* raw VBI */
1031 if (is_50hz)
1032 for (i = 6; i <= 23; i++)
1033 lcr[i] = 0xdd;
1034 else
1035 for (i = 10; i <= 21; i++)
1036 lcr[i] = 0xdd;
1037 } else {
1038 /* sliced VBI */
1039 /* first clear lines that cannot be captured */
1040 if (is_50hz) {
1041 for (i = 0; i <= 5; i++)
1042 fmt->service_lines[0][i] =
1043 fmt->service_lines[1][i] = 0;
1044 }
1045 else {
1046 for (i = 0; i <= 9; i++)
1047 fmt->service_lines[0][i] =
1048 fmt->service_lines[1][i] = 0;
1049 for (i = 22; i <= 23; i++)
1050 fmt->service_lines[0][i] =
1051 fmt->service_lines[1][i] = 0;
1052 }
1053
1054 /* Now set the lcr values according to the specified service */
1055 for (i = 6; i <= 23; i++) {
1056 lcr[i] = 0;
1057 for (x = 0; x <= 1; x++) {
1058 switch (fmt->service_lines[1-x][i]) {
1059 case 0:
1060 lcr[i] |= 0xf << (4 * x);
1061 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001062 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001063 lcr[i] |= 1 << (4 * x);
1064 break;
1065 case V4L2_SLICED_CAPTION_525:
1066 lcr[i] |= 4 << (4 * x);
1067 break;
1068 case V4L2_SLICED_WSS_625:
1069 lcr[i] |= 5 << (4 * x);
1070 break;
1071 case V4L2_SLICED_VPS:
1072 lcr[i] |= 7 << (4 * x);
1073 break;
1074 }
1075 }
1076 }
1077 }
1078
1079 /* write the lcr registers */
1080 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001081 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001082 }
1083
1084 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001085 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001086 saa7115_cfg_vbi_on :
1087 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001088}
1089
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001090static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001091{
1092 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001093 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001094 0, V4L2_SLICED_CAPTION_525, /* 4 */
1095 V4L2_SLICED_WSS_625, 0, /* 5 */
1096 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1097 0, 0, 0, 0
1098 };
1099 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1100 int i;
1101
1102 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1103 return -EINVAL;
1104 memset(sliced, 0, sizeof(*sliced));
1105 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001106 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001107 return 0;
1108 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001109 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001110
1111 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1112 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1113 sliced->service_set |=
1114 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1115 }
1116 return 0;
1117}
1118
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001119static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001120{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001121 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001122 struct v4l2_pix_format *pix;
1123 int HPSC, HFSC;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001124 int VSCY;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001125 int is_50hz = state->std & V4L2_STD_625_50;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001126 int Vsrc = is_50hz ? 576 : 480;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001127
1128 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001129 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001130 return 0;
1131 }
1132 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1133 return -EINVAL;
1134
1135 pix = &(fmt->fmt.pix);
1136
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001137 v4l_dbg(1, debug, client, "decoder set size\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001138
1139 /* FIXME need better bounds checking here */
1140 if ((pix->width < 1) || (pix->width > 1440))
1141 return -EINVAL;
1142 if ((pix->height < 1) || (pix->height > 960))
1143 return -EINVAL;
1144
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001145 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
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001153 /* probably have a valid size, let's set it */
1154 /* Set output width/height */
1155 /* width */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001156
1157 if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001158 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001159 (u8) (pix->width & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001160 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001161 (u8) ((pix->width >> 8) & 0xff));
1162 /* height */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001163 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001164 (u8) (pix->height & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001165 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001166 (u8) ((pix->height >> 8) & 0xff));
1167 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168
1169 /* Scaling settings */
1170 /* Hprescaler is floor(inres/outres) */
1171 /* FIXME hardcoding input res */
1172 if (pix->width != 720) {
1173 HPSC = (int)(720 / pix->width);
1174 /* 0 is not allowed (div. by zero) */
1175 HPSC = HPSC ? HPSC : 1;
1176 HFSC = (int)((1024 * 720) / (HPSC * pix->width));
1177
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001178 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001179 /* FIXME hardcodes to "Task B"
1180 * write H prescaler integer */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001181 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001182 (u8) (HPSC & 0x3f));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001183
1184 /* write H fine-scaling (luminance) */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001185 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001186 (u8) (HFSC & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001187 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001188 (u8) ((HFSC >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001189 /* write H fine-scaling (chrominance)
1190 * must be lum/2, so i'll just bitshift :) */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001191 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001192 (u8) ((HFSC >> 1) & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001193 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001194 (u8) ((HFSC >> 9) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001195 } else {
1196 if (is_50hz) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001197 v4l_dbg(1, debug, client, "Setting full 50hz width\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001198 saa711x_writeregs(client, saa7115_cfg_50hz_fullres_x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001199 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001200 v4l_dbg(1, debug, client, "Setting full 60hz width\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001201 saa711x_writeregs(client, saa7115_cfg_60hz_fullres_x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001202 }
1203 }
1204
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001205 if (pix->height != Vsrc) {
1206 VSCY = (int)((1024 * Vsrc) / pix->height);
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001207 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001208
1209 /* Correct Contrast and Luminance */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001210 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001211 (u8) (64 * 1024 / VSCY));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001212 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001213 (u8) (64 * 1024 / VSCY));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001214
1215 /* write V fine-scaling (luminance) */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001216 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001217 (u8) (VSCY & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001218 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001219 (u8) ((VSCY >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001220 /* write V fine-scaling (chrominance) */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001221 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001222 (u8) (VSCY & 0xff));
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001223 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001224 (u8) ((VSCY >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001225 } else {
1226 if (is_50hz) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001227 v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001228 saa711x_writeregs(client, saa7115_cfg_50hz_fullres_y);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001229 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001230 v4l_dbg(1, debug, client, "Setting full 60hz height\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001231 saa711x_writeregs(client, saa7115_cfg_60hz_fullres_y);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001232 }
1233 }
1234
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001235 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001236
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001237 return 0;
1238}
1239
1240/* Decode the sliced VBI data stream as created by the saa7115.
1241 The format is described in the saa7115 datasheet in Tables 25 and 26
1242 and in Figure 33.
1243 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001244 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001245 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001246static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001247 struct v4l2_decode_vbi_line *vbi)
1248{
1249 static const char vbi_no_data_pattern[] = {
1250 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1251 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001252 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001253 u8 *p = vbi->p;
1254 u32 wss;
1255 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1256
1257 vbi->type = 0; /* mark result as a failure */
1258 id1 = p[2];
1259 id2 = p[3];
1260 /* Note: the field bit is inverted for 60 Hz video */
1261 if (state->std & V4L2_STD_525_60)
1262 id1 ^= 0x40;
1263
1264 /* Skip internal header, p now points to the start of the payload */
1265 p += 4;
1266 vbi->p = p;
1267
1268 /* calculate field and line number of the VBI packet (1-23) */
1269 vbi->is_second_field = ((id1 & 0x40) != 0);
1270 vbi->line = (id1 & 0x3f) << 3;
1271 vbi->line |= (id2 & 0x70) >> 4;
1272
1273 /* Obtain data type */
1274 id2 &= 0xf;
1275
1276 /* If the VBI slicer does not detect any signal it will fill up
1277 the payload buffer with 0xa0 bytes. */
1278 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1279 return;
1280
1281 /* decode payloads */
1282 switch (id2) {
1283 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001284 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001285 break;
1286 case 4:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001287 if (!saa711x_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001288 return;
1289 vbi->type = V4L2_SLICED_CAPTION_525;
1290 break;
1291 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001292 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001293 if (wss == -1)
1294 return;
1295 p[0] = wss & 0xff;
1296 p[1] = wss >> 8;
1297 vbi->type = V4L2_SLICED_WSS_625;
1298 break;
1299 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001300 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001301 return;
1302 vbi->type = V4L2_SLICED_VPS;
1303 break;
1304 default:
1305 return;
1306 }
1307}
1308
1309/* ============ SAA7115 AUDIO settings (end) ============= */
1310
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001311static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001312{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001313 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001314 int *iarg = arg;
1315
1316 /* ioctls to allow direct access to the saa7115 registers for testing */
1317 switch (cmd) {
1318 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001319 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001320
1321 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001322 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001323
1324 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001325 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001326
1327 case VIDIOC_G_TUNER:
1328 {
1329 struct v4l2_tuner *vt = arg;
1330 int status;
1331
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001332 if (state->radio)
1333 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001334 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001335
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001336 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001337 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1338 break;
1339 }
1340
1341 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001342 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001343 break;
1344
1345 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001346 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001347
1348 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001349 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001350
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001351 case VIDIOC_QUERYCTRL:
1352 {
1353 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001354
Hans Verkuil18318e02006-06-18 14:49:52 -03001355 switch (qc->id) {
1356 case V4L2_CID_BRIGHTNESS:
1357 case V4L2_CID_CONTRAST:
1358 case V4L2_CID_SATURATION:
1359 case V4L2_CID_HUE:
1360 return v4l2_ctrl_query_fill_std(qc);
1361 default:
1362 return -EINVAL;
1363 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001364 }
1365
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001366 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001367 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001368 break;
1369
1370 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001371 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001372 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001373 break;
1374
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001375 case AUDC_SET_RADIO:
1376 state->radio = 1;
1377 break;
1378
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001379 case VIDIOC_INT_G_VIDEO_ROUTING:
1380 {
1381 struct v4l2_routing *route = arg;
1382
1383 route->input = state->input;
1384 route->output = 0;
1385 break;
1386 }
1387
1388 case VIDIOC_INT_S_VIDEO_ROUTING:
1389 {
1390 struct v4l2_routing *route = arg;
1391
1392 v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
1393 /* saa7113 does not have these inputs */
1394 if (state->ident == V4L2_IDENT_SAA7113 &&
1395 (route->input == SAA7115_COMPOSITE4 ||
1396 route->input == SAA7115_COMPOSITE5)) {
1397 return -EINVAL;
1398 }
1399 if (route->input > SAA7115_SVIDEO3)
1400 return -EINVAL;
1401 if (state->input == route->input)
1402 break;
1403 v4l_dbg(1, debug, client, "now setting %s input\n",
1404 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
1405 state->input = route->input;
1406
1407 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001408 saa711x_write(client, R_02_INPUT_CNTL_1,
1409 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001410 state->input);
1411
1412 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001413 saa711x_write(client, R_09_LUMA_CNTL,
1414 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001415 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1416 break;
1417 }
1418
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001419 case VIDIOC_STREAMON:
1420 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001421 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001422 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1423
1424 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1425 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001426 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001427 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1428 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001429 }
1430 break;
1431
Hans Verkuilb7f82922006-04-02 12:50:42 -03001432 case VIDIOC_INT_S_CRYSTAL_FREQ:
1433 {
1434 struct v4l2_crystal_freq *freq = arg;
1435
1436 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1437 freq->freq != SAA7115_FREQ_24_576_MHZ)
1438 return -EINVAL;
1439 state->crystal_freq = freq->freq;
1440 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1441 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1442 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001443 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001444 break;
1445 }
1446
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001447 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001448 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001449 break;
1450
1451 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001452 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001453 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001454 break;
1455
1456 case VIDIOC_INT_G_VBI_DATA:
1457 {
1458 struct v4l2_sliced_vbi_data *data = arg;
1459
1460 switch (data->id) {
1461 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001462 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001463 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001464 data->data[0] = saa711x_read(client, 0x6c);
1465 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001466 return 0;
1467 case V4L2_SLICED_CAPTION_525:
1468 if (data->field == 0) {
1469 /* CC */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001470 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001471 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001472 data->data[0] = saa711x_read(client, 0x67);
1473 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001474 return 0;
1475 }
1476 /* XDS */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001477 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001478 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001479 data->data[0] = saa711x_read(client, 0x69);
1480 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001481 return 0;
1482 default:
1483 return -EINVAL;
1484 }
1485 break;
1486 }
1487
1488#ifdef CONFIG_VIDEO_ADV_DEBUG
1489 case VIDIOC_INT_G_REGISTER:
1490 {
1491 struct v4l2_register *reg = arg;
1492
1493 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1494 return -EINVAL;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001495 reg->val = saa711x_read(client, reg->reg & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001496 break;
1497 }
1498
1499 case VIDIOC_INT_S_REGISTER:
1500 {
1501 struct v4l2_register *reg = arg;
1502
1503 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1504 return -EINVAL;
1505 if (!capable(CAP_SYS_ADMIN))
1506 return -EPERM;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001507 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001508 break;
1509 }
1510#endif
1511
1512 case VIDIOC_INT_G_CHIP_IDENT:
1513 *iarg = state->ident;
1514 break;
1515
1516 default:
1517 return -EINVAL;
1518 }
1519
1520 return 0;
1521}
1522
1523/* ----------------------------------------------------------------------- */
1524
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001525static struct i2c_driver i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001526
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001527static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001528{
1529 struct i2c_client *client;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001530 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001531 int i;
1532 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001533 u8 chip_id;
1534
1535 /* Check if the adapter supports the needed features */
1536 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1537 return 0;
1538
Panagiotis Issaris74081872006-01-11 19:40:56 -02001539 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001540 if (client == 0)
1541 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001542 client->addr = address;
1543 client->adapter = adapter;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001544 client->driver = &i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001545 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1546
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001547 v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001548
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001549 for (i=0;i<0x0f;i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001550 saa711x_write(client, 0, i);
1551 name[i] = (saa711x_read(client, 0) &0x0f) +'0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001552 if (name[i]>'9')
1553 name[i]+='a'-'9'-1;
1554 }
1555 name[i]='\0';
1556
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001557 saa711x_write(client, 0, 5);
1558 chip_id = saa711x_read(client, 0) & 0x0f;
Hans Verkuil01342352006-03-25 08:19:47 -03001559 if (chip_id < 3 && chip_id > 5) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001560 v4l_dbg(1, debug, client, "saa7115 not found\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001561 kfree(client);
1562 return 0;
1563 }
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001564 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001565 v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001566
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001567 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001568 i2c_set_clientdata(client, state);
1569 if (state == NULL) {
1570 kfree(client);
1571 return -ENOMEM;
1572 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001573 state->std = V4L2_STD_NTSC;
1574 state->input = -1;
1575 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001576 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001577 state->bright = 128;
1578 state->contrast = 64;
1579 state->hue = 0;
1580 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001581 switch (chip_id) {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001582 case 1:
1583 state->ident = V4L2_IDENT_SAA7111;
1584 break;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001585 case 3:
1586 state->ident = V4L2_IDENT_SAA7113;
1587 break;
1588 case 4:
1589 state->ident = V4L2_IDENT_SAA7114;
1590 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001591 case 5:
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001592 state->ident = V4L2_IDENT_SAA7115;
1593 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001594 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
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001601 }
1602
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001603 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001604
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001605 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001606
1607 /* init to 60hz/48khz */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001608 if (state->ident == V4L2_IDENT_SAA7111 ||
1609 state->ident == V4L2_IDENT_SAA7113) {
Hans Verkuilb7f82922006-04-02 12:50:42 -03001610 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001611 saa711x_writeregs(client, saa7113_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001612 } else {
1613 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001614 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001615 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001616 saa711x_writeregs(client, saa7115_init_misc);
1617 saa711x_writeregs(client, saa7115_cfg_60hz_fullres_x);
1618 saa711x_writeregs(client, saa7115_cfg_60hz_fullres_y);
1619 saa711x_writeregs(client, saa7115_cfg_60hz_video);
1620 saa711x_set_audio_clock_freq(client, state->audclk_freq);
1621 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001622
1623 i2c_attach_client(client);
1624
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001625 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001626 saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa7115_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001627
1628 return 0;
1629}
1630
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001631static int saa711x_probe(struct i2c_adapter *adapter)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001632{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001633 if (adapter->class & I2C_CLASS_TV_ANALOG)
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001634 return i2c_probe(adapter, &addr_data, &saa711x_attach);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001635 return 0;
1636}
1637
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001638static int saa711x_detach(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001639{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001640 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001641 int err;
1642
1643 err = i2c_detach_client(client);
1644 if (err) {
1645 return err;
1646 }
1647
1648 kfree(state);
1649 kfree(client);
1650 return 0;
1651}
1652
1653/* ----------------------------------------------------------------------- */
1654
1655/* i2c implementation */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001656static struct i2c_driver i2c_driver_saa711x = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001657 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001658 .name = "saa7115",
1659 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001660 .id = I2C_DRIVERID_SAA711X,
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001661 .attach_adapter = saa711x_probe,
1662 .detach_client = saa711x_detach,
1663 .command = saa711x_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001664};
1665
1666
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001667static int __init saa711x_init_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001668{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001669 return i2c_add_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001670}
1671
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001672static void __exit saa711x_cleanup_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001673{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001674 i2c_del_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001675}
1676
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001677module_init(saa711x_init_module);
1678module_exit(saa711x_cleanup_module);