blob: 987f540bc161a814c106680f93eb4c548fda8dce [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
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800273static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300274 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
275 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800276
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300277 R_15_VGATE_START_FID_CHG, 0x03,
278 R_16_VGATE_STOP, 0x11,
279 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800280
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300281 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
282 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800283
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300284 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800285
286 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300287 R_90_A_TASK_HANDLING_CNTL, 0x80,
288 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
289 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
290 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
291
292 /* hoffset low (input), 0x0002 is minimum */
293 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
294 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
295
296 /* hsize low (input), 0x02d0 = 720 */
297 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
298 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
299
300 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
301 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
302
303 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
304 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
305
306 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
307 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
308
309 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
310 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800311
312 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300313 R_C0_B_TASK_HANDLING_CNTL, 0x00,
314 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
315 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
316 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800317
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300318 /* 0x0002 is minimum */
319 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
320 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800321
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300322 /* 0x02d0 = 720 */
323 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
324 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
325
326 /* vwindow start 0x12 = 18 */
327 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
328 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
329
330 /* vwindow length 0xf8 = 248 */
331 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0xf8,
332 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
333
334 /* hwindow 0x02d0 = 720 */
335 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
336 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
337
338 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
339 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
340 R_F5_PULSGEN_LINE_LENGTH, 0xad,
341 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
342
343 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
344 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
345 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
346 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
347 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800348 0x00, 0x00
349};
350
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800351static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300352 R_80_GLOBAL_CNTL_1, 0x00,
353 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800354
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300355 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
356 R_16_VGATE_STOP, 0x16,
357 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800358
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300359 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
360 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800361
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300362 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800363
364 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300365 R_90_A_TASK_HANDLING_CNTL, 0x81,
366 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
367 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
368 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
369
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800370 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
371 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300372 /* hoffset low (input), 0x0002 is minimum */
373 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
374 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
375
376 /* hsize low (input), 0x02d0 = 720 */
377 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
378 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
379
380 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
381 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
382
383 /* vsize 0x12 = 18 */
384 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
385 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
386
387 /* hsize 0x05a0 = 1440 */
388 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
389 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
390 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
391 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800392
393 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300394 R_C0_B_TASK_HANDLING_CNTL, 0x00,
395 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
396 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
397 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800398
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300399 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
400 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
401 /* hoffset low (input), 0x0002 is minimum. See comment above. */
402 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
403 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800404
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300405 /* hsize 0x02d0 = 720 */
406 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
407 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
408
409 /* voffset 0x16 = 22 */
410 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
411 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
412
413 /* vsize 0x0120 = 288 */
414 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
415 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
416
417 /* hsize 0x02d0 = 720 */
418 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
419 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
420
421 /* vsize 0x0120 = 288 */
422 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
423 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
424
425 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
426 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
427 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
428 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
429
430 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
431 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler (was 0xD0) */
432 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
433 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
434 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
435
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800436 0x00, 0x00
437};
438
439/* ============== SAA7715 VIDEO templates (end) ======= */
440
441static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300442 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
443 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
444 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
445 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
446 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
447
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800448 0x00, 0x00
449};
450
451static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300452 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
453 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
454 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
455 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
456 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
457
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800458 0x00, 0x00
459};
460
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300461
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800462static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300463 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
464 0x82, 0x00, /* Reserved register - value should be zero*/
465 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
466 R_84_I_PORT_SIGNAL_DEF, 0x20,
467 R_85_I_PORT_SIGNAL_POLAR, 0x21,
468 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
469 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800470
471 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300472 R_A0_A_HORIZ_PRESCALING, 0x01,
473 R_A1_A_ACCUMULATION_LENGTH, 0x00,
474 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800475
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300476 /* Configure controls at nominal value*/
477 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
478 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
479 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
480
481 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
482 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
483 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
484
485 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
486
487 /* must be horiz lum scaling / 2 */
488 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
489 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
490
491 /* must be offset luma / 2 */
492 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
493
494 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
495 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
496
497 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
498 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
499
500 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
501
502 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
503 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
504 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
505 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
506
507 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
508 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
509 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
510 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800511
512 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300513 R_D0_B_HORIZ_PRESCALING, 0x01,
514 R_D1_B_ACCUMULATION_LENGTH, 0x00,
515 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800516
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300517 /* Configure controls at nominal value*/
518 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
519 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
520 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800521
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300522 /* hor lum scaling 0x0400 = 1 */
523 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
524 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
525
526 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
527
528 /* must be hor lum scaling / 2 */
529 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
530 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
531
532 /* must be offset luma / 2 */
533 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
534
535 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
536 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
537
538 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
539 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
540
541 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
542
543 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
544 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
545 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
546 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
547
548 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
549 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
550 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
551 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
552
553 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
554 R_F3_PLL_INCREMENT, 0x46,
555 R_F4_PLL2_STATUS, 0x00,
556 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
557 R_F8_PULSE_B_POS, 0x00,
558 R_F9_PULSE_B_POS_MSB, 0x4b,
559 R_FA_PULSE_C_POS, 0x00,
560 R_FB_PULSE_C_POS_MSB, 0x4b,
561
562 /* PLL2 lock detection settings: 71 lines 50% phase error */
563 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800564
565 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300566 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
567 R_41_LCR_BASE, 0xff,
568 R_41_LCR_BASE+1, 0xff,
569 R_41_LCR_BASE+2, 0xff,
570 R_41_LCR_BASE+3, 0xff,
571 R_41_LCR_BASE+4, 0xff,
572 R_41_LCR_BASE+5, 0xff,
573 R_41_LCR_BASE+6, 0xff,
574 R_41_LCR_BASE+7, 0xff,
575 R_41_LCR_BASE+8, 0xff,
576 R_41_LCR_BASE+9, 0xff,
577 R_41_LCR_BASE+10, 0xff,
578 R_41_LCR_BASE+11, 0xff,
579 R_41_LCR_BASE+12, 0xff,
580 R_41_LCR_BASE+13, 0xff,
581 R_41_LCR_BASE+14, 0xff,
582 R_41_LCR_BASE+15, 0xff,
583 R_41_LCR_BASE+16, 0xff,
584 R_41_LCR_BASE+17, 0xff,
585 R_41_LCR_BASE+18, 0xff,
586 R_41_LCR_BASE+19, 0xff,
587 R_41_LCR_BASE+20, 0xff,
588 R_41_LCR_BASE+21, 0xff,
589 R_41_LCR_BASE+22, 0xff,
590 R_58_PROGRAM_FRAMING_CODE, 0x40,
591 R_59_H_OFF_FOR_SLICER, 0x47,
592 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
593 R_5D_DID, 0xbd,
594 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800595
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300596 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
597 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800598
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300599 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
600 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
601 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800602 0x00, 0x00
603};
604
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300605static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800606{
607 c ^= (c >> 4);
608 c ^= (c >> 2);
609 c ^= (c >> 1);
610
611 return c & 1;
612}
613
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300614static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800615{
616 static const u8 biphase_tbl[] = {
617 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
618 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
619 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
620 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
621 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
622 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
623 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
624 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
625 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
626 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
627 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
628 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
629 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
630 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
631 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
632 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
633 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
634 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
635 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
636 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
637 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
638 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
639 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
640 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
641 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
642 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
643 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
644 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
645 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
646 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
647 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
648 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
649 };
650 int i;
651 u8 c, err = 0;
652
653 for (i = 0; i < 2 * 13; i += 2) {
654 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
655 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
656 dst[i / 2] = c;
657 }
658 return err & 0xf0;
659}
660
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300661static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800662{
663 static const int wss_bits[8] = {
664 0, 0, 0, 1, 0, 1, 1, 1
665 };
666 unsigned char parity;
667 int wss = 0;
668 int i;
669
670 for (i = 0; i < 16; i++) {
671 int b1 = wss_bits[p[i] & 7];
672 int b2 = wss_bits[(p[i] >> 3) & 7];
673
674 if (b1 == b2)
675 return -1;
676 wss |= b2 << i;
677 }
678 parity = wss & 15;
679 parity ^= parity >> 2;
680 parity ^= parity >> 1;
681
682 if (!(parity & 1))
683 return -1;
684
685 return wss;
686}
687
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300688static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800689{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300690 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200691 u32 acpf;
692 u32 acni;
693 u32 hz;
694 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300695 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800696
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300697 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
698 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
699 return 0;
700
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200701 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200702
703 /* sanity check */
704 if (freq < 32000 || freq > 48000)
705 return -EINVAL;
706
707 /* hz is the refresh rate times 100 */
708 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
709 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
710 acpf = (25600 * freq) / hz;
711 /* acni = (256 * freq * 2^23) / crystal_frequency =
712 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300713 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200714 f = freq;
715 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300716 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200717 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300718 if (state->ucgc) {
719 acpf = acpf * state->cgcdiv / 16;
720 acni = acni * state->cgcdiv / 16;
721 acc = 0x80;
722 if (state->cgcdiv == 3)
723 acc |= 0x40;
724 }
725 if (state->apll)
726 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200727
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300728 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
729 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
730 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300731
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300732 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
733 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300734 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300735 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300736 (acpf >> 16) & 0x03);
737
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300738 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
739 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
740 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800741 state->audclk_freq = freq;
742 return 0;
743}
744
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300745static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800746{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300747 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800748
749 switch (ctrl->id) {
750 case V4L2_CID_BRIGHTNESS:
751 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200752 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800753 return -ERANGE;
754 }
755
756 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300757 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800758 break;
759
760 case V4L2_CID_CONTRAST:
761 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200762 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800763 return -ERANGE;
764 }
765
766 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300767 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800768 break;
769
770 case V4L2_CID_SATURATION:
771 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200772 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800773 return -ERANGE;
774 }
775
776 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300777 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800778 break;
779
780 case V4L2_CID_HUE:
781 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200782 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800783 return -ERANGE;
784 }
785
786 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300787 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800788 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200789
790 default:
791 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800792 }
793
794 return 0;
795}
796
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300797static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800798{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300799 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800800
801 switch (ctrl->id) {
802 case V4L2_CID_BRIGHTNESS:
803 ctrl->value = state->bright;
804 break;
805 case V4L2_CID_CONTRAST:
806 ctrl->value = state->contrast;
807 break;
808 case V4L2_CID_SATURATION:
809 ctrl->value = state->sat;
810 break;
811 case V4L2_CID_HUE:
812 ctrl->value = state->hue;
813 break;
814 default:
815 return -EINVAL;
816 }
817
818 return 0;
819}
820
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300821static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800822{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300823 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800824
Hans Verkuil30b54d52006-01-09 15:25:43 -0200825 /* Prevent unnecessary standard changes. During a standard
826 change the I-Port is temporarily disabled. Any devices
827 reading from that port can get confused.
828 Note that VIDIOC_S_STD is also used to switch from
829 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
830 all I2C devices then you do not want to have an unwanted
831 side-effect here. */
832 if (std == state->std)
833 return;
834
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800835 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
836 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200837 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300838 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800839 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200840 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300841 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800842 }
843
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300844 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300845 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300846 50 Hz / 625 lines 60 Hz / 525 lines
847 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
848 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
849 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
850 011 NTSC N (3.58MHz) PAL M (3.58MHz)
851 100 reserved NTSC-Japan (3.58MHz)
852 */
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -0300853 state->std = std;
854
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300855 if (state->ident == V4L2_IDENT_SAA7111 ||
856 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300857 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300858
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300859 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300860 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300861 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300862 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300863 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300864 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300865 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300866 reg |= 0x40;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300867 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300868 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300869 } else {
870 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300871 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300872
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300873 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300874 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300875 }
876
877 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300878 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300879 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800880}
881
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300882static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800883{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300884 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800885
886 return state->std;
887}
888
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300889static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800890{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300891 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800892 int reg1e, reg1f;
893 int signalOk;
894 int vcr;
895
Hans Verkuilfac9e892006-01-09 15:32:40 -0200896 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300897 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800898 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300899 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800900 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200901 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
902 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800903 return;
904 }
905
906 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300907 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
908 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800909
910 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
911 vcr = !(reg1f & 0x10);
912
Hans Verkuil21fa7152006-01-09 15:25:41 -0200913 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200914 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200915 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200916 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200917 }
Hans Verkuilfac9e892006-01-09 15:32:40 -0200918 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
919 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800920
921 switch (reg1e & 0x03) {
922 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200923 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800924 break;
925 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200926 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800927 break;
928 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200929 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800930 break;
931 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200932 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800933 break;
934 }
935}
936
937/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300938static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800939{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300940 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800941 int is_50hz = (state->std & V4L2_STD_625_50);
942 u8 lcr[24];
943 int i, x;
944
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300945#if 1
946 /* saa7113/7114/7118 VBI support are experimental */
947 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
948 return;
949
950#else
951 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300952 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800953 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300954#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800955
956 for (i = 0; i <= 23; i++)
957 lcr[i] = 0xff;
958
959 if (fmt->service_set == 0) {
960 /* raw VBI */
961 if (is_50hz)
962 for (i = 6; i <= 23; i++)
963 lcr[i] = 0xdd;
964 else
965 for (i = 10; i <= 21; i++)
966 lcr[i] = 0xdd;
967 } else {
968 /* sliced VBI */
969 /* first clear lines that cannot be captured */
970 if (is_50hz) {
971 for (i = 0; i <= 5; i++)
972 fmt->service_lines[0][i] =
973 fmt->service_lines[1][i] = 0;
974 }
975 else {
976 for (i = 0; i <= 9; i++)
977 fmt->service_lines[0][i] =
978 fmt->service_lines[1][i] = 0;
979 for (i = 22; i <= 23; i++)
980 fmt->service_lines[0][i] =
981 fmt->service_lines[1][i] = 0;
982 }
983
984 /* Now set the lcr values according to the specified service */
985 for (i = 6; i <= 23; i++) {
986 lcr[i] = 0;
987 for (x = 0; x <= 1; x++) {
988 switch (fmt->service_lines[1-x][i]) {
989 case 0:
990 lcr[i] |= 0xf << (4 * x);
991 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -0300992 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800993 lcr[i] |= 1 << (4 * x);
994 break;
995 case V4L2_SLICED_CAPTION_525:
996 lcr[i] |= 4 << (4 * x);
997 break;
998 case V4L2_SLICED_WSS_625:
999 lcr[i] |= 5 << (4 * x);
1000 break;
1001 case V4L2_SLICED_VPS:
1002 lcr[i] |= 7 << (4 * x);
1003 break;
1004 }
1005 }
1006 }
1007 }
1008
1009 /* write the lcr registers */
1010 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001011 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001012 }
1013
1014 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001015 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001016 saa7115_cfg_vbi_on :
1017 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001018}
1019
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001020static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001021{
1022 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001023 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001024 0, V4L2_SLICED_CAPTION_525, /* 4 */
1025 V4L2_SLICED_WSS_625, 0, /* 5 */
1026 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1027 0, 0, 0, 0
1028 };
1029 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1030 int i;
1031
1032 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1033 return -EINVAL;
1034 memset(sliced, 0, sizeof(*sliced));
1035 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001036 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001037 return 0;
1038 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001039 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001040
1041 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1042 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1043 sliced->service_set |=
1044 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1045 }
1046 return 0;
1047}
1048
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001049static int saa711x_set_size(struct i2c_client *client, int width, int height)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001050{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001051 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001052 int HPSC, HFSC;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001053 int VSCY;
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001054 int res;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001055 int is_50hz = state->std & V4L2_STD_625_50;
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001056 int Vsrc = is_50hz ? 576 : 480+16;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001057
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001058 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
1059
1060 /* FIXME need better bounds checking here */
1061 if ((width < 1) || (width > 1440))
1062 return -EINVAL;
1063 if ((height < 1) || (height > 960))
1064 return -EINVAL;
1065
1066 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
1067 /* Decoder only supports 720 columns and 480 or 576 lines */
1068 if (width != 720)
1069 return -EINVAL;
1070 if (height != Vsrc)
1071 return -EINVAL;
1072 }
1073 if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
1074 return 0;
1075
1076 /* probably have a valid size, let's set it */
1077 /* Set output width/height */
1078 /* width */
1079
1080 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
1081 (u8) (width & 0xff));
1082 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
1083 (u8) ((width >> 8) & 0xff));
1084
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001085 /* Vertical Scaling uses height/2 */
1086 res=height/2;
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001087
1088 /* height */
1089 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
1090 (u8) (res & 0xff));
1091 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001092 (u8) ((res >> 8) & 0xff));
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001093
1094 /* Scaling settings */
1095 /* Hprescaler is floor(inres/outres) */
1096 HPSC = (int)(720 / width);
1097 /* 0 is not allowed (div. by zero) */
1098 HPSC = HPSC ? HPSC : 1;
1099 HFSC = (int)((1024 * 720) / (HPSC * width));
1100 /* FIXME hardcodes to "Task B"
1101 * write H prescaler integer */
1102 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
1103 (u8) (HPSC & 0x3f));
1104
1105 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
1106 /* write H fine-scaling (luminance) */
1107 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
1108 (u8) (HFSC & 0xff));
1109 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
1110 (u8) ((HFSC >> 8) & 0xff));
1111 /* write H fine-scaling (chrominance)
1112 * must be lum/2, so i'll just bitshift :) */
1113 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
1114 (u8) ((HFSC >> 1) & 0xff));
1115 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
1116 (u8) ((HFSC >> 9) & 0xff));
1117
1118 VSCY = (int)((1024 * Vsrc) / height);
1119 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
1120
1121 /* Correct Contrast and Luminance */
1122 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
1123 (u8) (64 * 1024 / VSCY));
1124 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
1125 (u8) (64 * 1024 / VSCY));
1126
1127 /* write V fine-scaling (luminance) */
1128 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
1129 (u8) (VSCY & 0xff));
1130 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
1131 (u8) ((VSCY >> 8) & 0xff));
1132 /* write V fine-scaling (chrominance) */
1133 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
1134 (u8) (VSCY & 0xff));
1135 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
1136 (u8) ((VSCY >> 8) & 0xff));
1137
1138 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
1139
1140 return 0;
1141}
1142
1143static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1144{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001145 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001146 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001147 return 0;
1148 }
1149 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1150 return -EINVAL;
1151
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001152 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001153}
1154
1155/* Decode the sliced VBI data stream as created by the saa7115.
1156 The format is described in the saa7115 datasheet in Tables 25 and 26
1157 and in Figure 33.
1158 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001159 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001160 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001161static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001162 struct v4l2_decode_vbi_line *vbi)
1163{
1164 static const char vbi_no_data_pattern[] = {
1165 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1166 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001167 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168 u8 *p = vbi->p;
1169 u32 wss;
1170 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1171
1172 vbi->type = 0; /* mark result as a failure */
1173 id1 = p[2];
1174 id2 = p[3];
1175 /* Note: the field bit is inverted for 60 Hz video */
1176 if (state->std & V4L2_STD_525_60)
1177 id1 ^= 0x40;
1178
1179 /* Skip internal header, p now points to the start of the payload */
1180 p += 4;
1181 vbi->p = p;
1182
1183 /* calculate field and line number of the VBI packet (1-23) */
1184 vbi->is_second_field = ((id1 & 0x40) != 0);
1185 vbi->line = (id1 & 0x3f) << 3;
1186 vbi->line |= (id2 & 0x70) >> 4;
1187
1188 /* Obtain data type */
1189 id2 &= 0xf;
1190
1191 /* If the VBI slicer does not detect any signal it will fill up
1192 the payload buffer with 0xa0 bytes. */
1193 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1194 return;
1195
1196 /* decode payloads */
1197 switch (id2) {
1198 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001199 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001200 break;
1201 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001202 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001203 return;
1204 vbi->type = V4L2_SLICED_CAPTION_525;
1205 break;
1206 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001207 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001208 if (wss == -1)
1209 return;
1210 p[0] = wss & 0xff;
1211 p[1] = wss >> 8;
1212 vbi->type = V4L2_SLICED_WSS_625;
1213 break;
1214 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001215 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001216 return;
1217 vbi->type = V4L2_SLICED_VPS;
1218 break;
1219 default:
1220 return;
1221 }
1222}
1223
1224/* ============ SAA7115 AUDIO settings (end) ============= */
1225
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001226static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001227{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001228 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001229 int *iarg = arg;
1230
1231 /* ioctls to allow direct access to the saa7115 registers for testing */
1232 switch (cmd) {
1233 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001234 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001235
1236 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001237 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001238
1239 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001240 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001241
1242 case VIDIOC_G_TUNER:
1243 {
1244 struct v4l2_tuner *vt = arg;
1245 int status;
1246
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001247 if (state->radio)
1248 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001249 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001250
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001251 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001252 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1253 break;
1254 }
1255
1256 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001257 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001258 break;
1259
1260 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001261 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001262
1263 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001264 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001265
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001266 case VIDIOC_QUERYCTRL:
1267 {
1268 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001269
Hans Verkuil18318e02006-06-18 14:49:52 -03001270 switch (qc->id) {
1271 case V4L2_CID_BRIGHTNESS:
1272 case V4L2_CID_CONTRAST:
1273 case V4L2_CID_SATURATION:
1274 case V4L2_CID_HUE:
1275 return v4l2_ctrl_query_fill_std(qc);
1276 default:
1277 return -EINVAL;
1278 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001279 }
1280
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001281 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001282 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001283 break;
1284
1285 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001286 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001287 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001288 break;
1289
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001290 case AUDC_SET_RADIO:
1291 state->radio = 1;
1292 break;
1293
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001294 case VIDIOC_INT_G_VIDEO_ROUTING:
1295 {
1296 struct v4l2_routing *route = arg;
1297
1298 route->input = state->input;
1299 route->output = 0;
1300 break;
1301 }
1302
1303 case VIDIOC_INT_S_VIDEO_ROUTING:
1304 {
1305 struct v4l2_routing *route = arg;
1306
1307 v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
1308 /* saa7113 does not have these inputs */
1309 if (state->ident == V4L2_IDENT_SAA7113 &&
1310 (route->input == SAA7115_COMPOSITE4 ||
1311 route->input == SAA7115_COMPOSITE5)) {
1312 return -EINVAL;
1313 }
1314 if (route->input > SAA7115_SVIDEO3)
1315 return -EINVAL;
1316 if (state->input == route->input)
1317 break;
1318 v4l_dbg(1, debug, client, "now setting %s input\n",
1319 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
1320 state->input = route->input;
1321
1322 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001323 saa711x_write(client, R_02_INPUT_CNTL_1,
1324 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001325 state->input);
1326
1327 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001328 saa711x_write(client, R_09_LUMA_CNTL,
1329 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001330 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1331 break;
1332 }
1333
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001334 case VIDIOC_STREAMON:
1335 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001336 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001337 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1338
1339 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1340 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001341 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001342 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1343 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001344 }
1345 break;
1346
Hans Verkuilb7f82922006-04-02 12:50:42 -03001347 case VIDIOC_INT_S_CRYSTAL_FREQ:
1348 {
1349 struct v4l2_crystal_freq *freq = arg;
1350
1351 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1352 freq->freq != SAA7115_FREQ_24_576_MHZ)
1353 return -EINVAL;
1354 state->crystal_freq = freq->freq;
1355 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1356 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1357 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001358 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001359 break;
1360 }
1361
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001362 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001363 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001364 break;
1365
1366 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001367 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001368 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001369 break;
1370
1371 case VIDIOC_INT_G_VBI_DATA:
1372 {
1373 struct v4l2_sliced_vbi_data *data = arg;
1374
1375 switch (data->id) {
1376 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001377 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001378 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001379 data->data[0] = saa711x_read(client, 0x6c);
1380 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001381 return 0;
1382 case V4L2_SLICED_CAPTION_525:
1383 if (data->field == 0) {
1384 /* CC */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001385 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001386 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001387 data->data[0] = saa711x_read(client, 0x67);
1388 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001389 return 0;
1390 }
1391 /* XDS */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001392 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001393 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001394 data->data[0] = saa711x_read(client, 0x69);
1395 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001396 return 0;
1397 default:
1398 return -EINVAL;
1399 }
1400 break;
1401 }
1402
1403#ifdef CONFIG_VIDEO_ADV_DEBUG
1404 case VIDIOC_INT_G_REGISTER:
1405 {
1406 struct v4l2_register *reg = arg;
1407
1408 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1409 return -EINVAL;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001410 reg->val = saa711x_read(client, reg->reg & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001411 break;
1412 }
1413
1414 case VIDIOC_INT_S_REGISTER:
1415 {
1416 struct v4l2_register *reg = arg;
1417
1418 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1419 return -EINVAL;
1420 if (!capable(CAP_SYS_ADMIN))
1421 return -EPERM;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001422 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001423 break;
1424 }
1425#endif
1426
1427 case VIDIOC_INT_G_CHIP_IDENT:
1428 *iarg = state->ident;
1429 break;
1430
1431 default:
1432 return -EINVAL;
1433 }
1434
1435 return 0;
1436}
1437
1438/* ----------------------------------------------------------------------- */
1439
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001440static struct i2c_driver i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001441
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001442static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001443{
1444 struct i2c_client *client;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001445 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001446 int i;
1447 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001448 u8 chip_id;
1449
1450 /* Check if the adapter supports the needed features */
1451 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1452 return 0;
1453
Panagiotis Issaris74081872006-01-11 19:40:56 -02001454 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001455 if (client == 0)
1456 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001457 client->addr = address;
1458 client->adapter = adapter;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001459 client->driver = &i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001460 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1461
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001462 v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001463
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001464 for (i=0;i<0x0f;i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001465 saa711x_write(client, 0, i);
1466 name[i] = (saa711x_read(client, 0) &0x0f) +'0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001467 if (name[i]>'9')
1468 name[i]+='a'-'9'-1;
1469 }
1470 name[i]='\0';
1471
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001472 saa711x_write(client, 0, 5);
1473 chip_id = saa711x_read(client, 0) & 0x0f;
Hans Verkuil01342352006-03-25 08:19:47 -03001474 if (chip_id < 3 && chip_id > 5) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001475 v4l_dbg(1, debug, client, "saa7115 not found\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001476 kfree(client);
1477 return 0;
1478 }
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001479 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001480 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 -08001481
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001482 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001483 i2c_set_clientdata(client, state);
1484 if (state == NULL) {
1485 kfree(client);
1486 return -ENOMEM;
1487 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001488 state->input = -1;
1489 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001490 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001491 state->bright = 128;
1492 state->contrast = 64;
1493 state->hue = 0;
1494 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001495 switch (chip_id) {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001496 case 1:
1497 state->ident = V4L2_IDENT_SAA7111;
1498 break;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001499 case 3:
1500 state->ident = V4L2_IDENT_SAA7113;
1501 break;
1502 case 4:
1503 state->ident = V4L2_IDENT_SAA7114;
1504 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001505 case 5:
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001506 state->ident = V4L2_IDENT_SAA7115;
1507 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001508 case 8:
1509 state->ident = V4L2_IDENT_SAA7118;
1510 break;
1511 default:
1512 state->ident = V4L2_IDENT_SAA7111;
1513 v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
1514
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001515 }
1516
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001517 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001518
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001519 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001520
1521 /* init to 60hz/48khz */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001522 if (state->ident == V4L2_IDENT_SAA7111 ||
1523 state->ident == V4L2_IDENT_SAA7113) {
Hans Verkuilb7f82922006-04-02 12:50:42 -03001524 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001525 saa711x_writeregs(client, saa7113_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001526 } else {
1527 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001528 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001529 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001530 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001531 state->std = V4L2_STD_NTSC;
1532 saa711x_set_size(client, 720, 480);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001533 saa711x_writeregs(client, saa7115_cfg_60hz_video);
1534 saa711x_set_audio_clock_freq(client, state->audclk_freq);
1535 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001536
1537 i2c_attach_client(client);
1538
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001539 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001540 saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001541
1542 return 0;
1543}
1544
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001545static int saa711x_probe(struct i2c_adapter *adapter)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001546{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001547 if (adapter->class & I2C_CLASS_TV_ANALOG)
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001548 return i2c_probe(adapter, &addr_data, &saa711x_attach);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001549 return 0;
1550}
1551
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001552static int saa711x_detach(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001553{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001554 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001555 int err;
1556
1557 err = i2c_detach_client(client);
1558 if (err) {
1559 return err;
1560 }
1561
1562 kfree(state);
1563 kfree(client);
1564 return 0;
1565}
1566
1567/* ----------------------------------------------------------------------- */
1568
1569/* i2c implementation */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001570static struct i2c_driver i2c_driver_saa711x = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001571 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001572 .name = "saa7115",
1573 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001574 .id = I2C_DRIVERID_SAA711X,
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001575 .attach_adapter = saa711x_probe,
1576 .detach_client = saa711x_detach,
1577 .command = saa711x_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001578};
1579
1580
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001581static int __init saa711x_init_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001582{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001583 return i2c_add_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001584}
1585
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001586static void __exit saa711x_cleanup_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001587{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001588 i2c_del_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001589}
1590
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001591module_init(saa711x_init_module);
1592module_exit(saa711x_cleanup_module);