blob: 2257e4e835a165522a5cab2f0249d7272c6144cb [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;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300101 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300102 case V4L2_IDENT_SAA7113:
103 if (reg>0x62 || reg==0x14 || (reg>=0x18 && reg<=0x1e) ||
104 (reg>=0x20 && reg<=0x3f) ||reg==0x5f )
105 return 0;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300106 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300107 case V4L2_IDENT_SAA7114:
108 if (reg>=0xf0 || (reg>=0x1a && reg<=0x1e) ||
109 (reg>=0x20 && reg<=0x2f) ||
110 (reg>=0x63 && reg<=0x7f) )
111 return 0;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300112 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300113 case V4L2_IDENT_SAA7115:
114 if ((reg>=0x20 && reg<=0x2f) || (reg==0x5c) ||
115 (reg>=0xfc && reg<=0xfe) )
116 return 0;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300117 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300118 case V4L2_IDENT_SAA7118:
119 if (reg>=0xf0 || (reg>=0x1a && reg<=0x1d) ||
120 (reg>=0x63 && reg<=0x6f) )
121 return 0;
122 }
123
124 /* Those registers are reserved for all family */
125 if (unlikely((reg>=0x20 && reg<=0x22) ||
126 (reg>=0x26 && reg<=0x28) ||
127 (reg>=0x3b && reg<=0x3f) || (reg==0x5f) ||
128 (reg>=0x63 && reg<=0x6f) ) )
129 return 0;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300130 return 1;
131}
132
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300133static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800134{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300135 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800136 unsigned char reg, data;
137
138 while (*regs != 0x00) {
139 reg = *(regs++);
140 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300141
142 /* According with datasheets, reserved regs should be
143 filled with 0 - seems better not to touch on they */
144 if (saa711x_has_reg(state->ident,reg)) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300145 if (saa711x_write(client, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300146 return -1;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300147 } else {
148 v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300149 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800150 }
151 return 0;
152}
153
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300154static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800155{
156 return i2c_smbus_read_byte_data(client, reg);
157}
158
159/* ----------------------------------------------------------------------- */
160
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300161/* SAA7111 initialization table */
162static const unsigned char saa7111_init_auto_input[] = {
163 R_01_INC_DELAY, 0x00, /* reserved */
164
165 /*front end */
166 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
167 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
168 * GAFIX=0, GAI1=256, GAI2=256 */
169 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
170 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
171
172 /* decoder */
173 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
174 * pixels after end of last line */
175 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
176 * work with NTSC, too */
177 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
178 * VTRC=1, HPLL=0, VNOI=0 */
179 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
180 * VBLB=0, UPTCV=0, APER=1 */
181 R_0A_LUMA_BRIGHT_CNTL, 0x80,
182 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
183 R_0C_CHROMA_SAT_CNTL, 0x40,
184 R_0D_CHROMA_HUE_CNTL, 0x00,
185 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
186 * FCTC=0, CHBW=1 */
187 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
188 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
189 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
190 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
191 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
192 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
193 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
194 R_15_VGATE_START_FID_CHG, 0x00,
195 R_16_VGATE_STOP, 0x00,
196 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
197
198 0x00, 0x00
199};
200
201/* SAA7113 init codes */
202static const unsigned char saa7113_init_auto_input[] = {
203 R_01_INC_DELAY, 0x08,
204 R_02_INPUT_CNTL_1, 0xc2,
205 R_03_INPUT_CNTL_2, 0x30,
206 R_04_INPUT_CNTL_3, 0x00,
207 R_05_INPUT_CNTL_4, 0x00,
208 R_06_H_SYNC_START, 0x89,
209 R_07_H_SYNC_STOP, 0x0d,
210 R_08_SYNC_CNTL, 0x88,
211 R_09_LUMA_CNTL, 0x01,
212 R_0A_LUMA_BRIGHT_CNTL, 0x80,
213 R_0B_LUMA_CONTRAST_CNTL, 0x47,
214 R_0C_CHROMA_SAT_CNTL, 0x40,
215 R_0D_CHROMA_HUE_CNTL, 0x00,
216 R_0E_CHROMA_CNTL_1, 0x01,
217 R_0F_CHROMA_GAIN_CNTL, 0x2a,
218 R_10_CHROMA_CNTL_2, 0x08,
219 R_11_MODE_DELAY_CNTL, 0x0c,
220 R_12_RT_SIGNAL_CNTL, 0x07,
221 R_13_RT_X_PORT_OUT_CNTL, 0x00,
222 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
223 R_15_VGATE_START_FID_CHG, 0x00,
224 R_16_VGATE_STOP, 0x00,
225 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
226
227 0x00, 0x00
228};
229
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800230/* If a value differs from the Hauppauge driver values, then the comment starts with
231 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
232 Hauppauge driver sets. */
233
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300234/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800235static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300236 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300237 R_01_INC_DELAY, 0x48, /* white peak control disabled */
238 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
239 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
240 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300241 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300242 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
243 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
244 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
245 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
246 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
247 R_0D_CHROMA_HUE_CNTL, 0x00,
248 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
249 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
250 R_11_MODE_DELAY_CNTL, 0x00,
251 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
252 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
253 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
254 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
255 R_19_RAW_DATA_OFF_CNTL, 0x80,
256 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
257 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
258 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
259 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300260
261 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300262 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
263 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800264 0x00, 0x00
265};
266
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300267/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800268static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300269 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
270 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
271 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
272 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800273 0x00, 0x00
274};
275
276/* ============== SAA7715 VIDEO templates ============= */
277
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800278static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300279 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
280 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800281
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300282 R_15_VGATE_START_FID_CHG, 0x03,
283 R_16_VGATE_STOP, 0x11,
284 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800285
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300286 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
287 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800288
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300289 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800290
291 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300292 R_90_A_TASK_HANDLING_CNTL, 0x80,
293 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
294 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
295 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
296
297 /* hoffset low (input), 0x0002 is minimum */
298 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
299 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
300
301 /* hsize low (input), 0x02d0 = 720 */
302 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
303 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
304
305 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
306 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
307
308 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
309 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
310
311 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
312 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
313
314 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
315 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800316
317 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300318 R_C0_B_TASK_HANDLING_CNTL, 0x00,
319 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
320 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
321 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800322
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300323 /* 0x0002 is minimum */
324 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
325 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800326
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300327 /* 0x02d0 = 720 */
328 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
329 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
330
331 /* vwindow start 0x12 = 18 */
332 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
333 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
334
335 /* vwindow length 0xf8 = 248 */
336 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0xf8,
337 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
338
339 /* hwindow 0x02d0 = 720 */
340 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
341 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
342
343 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
344 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
345 R_F5_PULSGEN_LINE_LENGTH, 0xad,
346 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
347
348 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
349 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
350 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
351 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
352 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800353 0x00, 0x00
354};
355
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800356static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300357 R_80_GLOBAL_CNTL_1, 0x00,
358 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800359
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300360 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
361 R_16_VGATE_STOP, 0x16,
362 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800363
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300364 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
365 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800366
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300367 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800368
369 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300370 R_90_A_TASK_HANDLING_CNTL, 0x81,
371 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
372 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
373 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
374
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800375 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
376 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300377 /* hoffset low (input), 0x0002 is minimum */
378 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
379 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
380
381 /* hsize low (input), 0x02d0 = 720 */
382 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
383 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
384
385 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
386 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
387
388 /* vsize 0x12 = 18 */
389 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
390 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
391
392 /* hsize 0x05a0 = 1440 */
393 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
394 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
395 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
396 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800397
398 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300399 R_C0_B_TASK_HANDLING_CNTL, 0x00,
400 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
401 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
402 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800403
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300404 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
405 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
406 /* hoffset low (input), 0x0002 is minimum. See comment above. */
407 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
408 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800409
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300410 /* hsize 0x02d0 = 720 */
411 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
412 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
413
414 /* voffset 0x16 = 22 */
415 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
416 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
417
418 /* vsize 0x0120 = 288 */
419 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
420 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
421
422 /* hsize 0x02d0 = 720 */
423 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
424 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
425
426 /* vsize 0x0120 = 288 */
427 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
428 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
429
430 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
431 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
432 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
433 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
434
435 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
436 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler (was 0xD0) */
437 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
438 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
439 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
440
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800441 0x00, 0x00
442};
443
444/* ============== SAA7715 VIDEO templates (end) ======= */
445
446static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300447 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
448 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
449 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
450 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
451 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
452
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800453 0x00, 0x00
454};
455
456static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300457 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
458 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
459 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
460 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
461 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
462
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800463 0x00, 0x00
464};
465
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300466
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800467static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300468 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
469 0x82, 0x00, /* Reserved register - value should be zero*/
470 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
471 R_84_I_PORT_SIGNAL_DEF, 0x20,
472 R_85_I_PORT_SIGNAL_POLAR, 0x21,
473 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
474 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800475
476 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300477 R_A0_A_HORIZ_PRESCALING, 0x01,
478 R_A1_A_ACCUMULATION_LENGTH, 0x00,
479 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800480
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300481 /* Configure controls at nominal value*/
482 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
483 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
484 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
485
486 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
487 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
488 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
489
490 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
491
492 /* must be horiz lum scaling / 2 */
493 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
494 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
495
496 /* must be offset luma / 2 */
497 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
498
499 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
500 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
501
502 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
503 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
504
505 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
506
507 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
508 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
509 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
510 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
511
512 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
513 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
514 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
515 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800516
517 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300518 R_D0_B_HORIZ_PRESCALING, 0x01,
519 R_D1_B_ACCUMULATION_LENGTH, 0x00,
520 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800521
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300522 /* Configure controls at nominal value*/
523 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
524 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
525 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800526
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300527 /* hor lum scaling 0x0400 = 1 */
528 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
529 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
530
531 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
532
533 /* must be hor lum scaling / 2 */
534 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
535 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
536
537 /* must be offset luma / 2 */
538 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
539
540 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
541 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
542
543 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
544 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
545
546 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
547
548 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
549 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
550 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
551 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
552
553 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
554 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
555 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
556 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
557
558 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
559 R_F3_PLL_INCREMENT, 0x46,
560 R_F4_PLL2_STATUS, 0x00,
561 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
562 R_F8_PULSE_B_POS, 0x00,
563 R_F9_PULSE_B_POS_MSB, 0x4b,
564 R_FA_PULSE_C_POS, 0x00,
565 R_FB_PULSE_C_POS_MSB, 0x4b,
566
567 /* PLL2 lock detection settings: 71 lines 50% phase error */
568 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800569
570 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300571 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
572 R_41_LCR_BASE, 0xff,
573 R_41_LCR_BASE+1, 0xff,
574 R_41_LCR_BASE+2, 0xff,
575 R_41_LCR_BASE+3, 0xff,
576 R_41_LCR_BASE+4, 0xff,
577 R_41_LCR_BASE+5, 0xff,
578 R_41_LCR_BASE+6, 0xff,
579 R_41_LCR_BASE+7, 0xff,
580 R_41_LCR_BASE+8, 0xff,
581 R_41_LCR_BASE+9, 0xff,
582 R_41_LCR_BASE+10, 0xff,
583 R_41_LCR_BASE+11, 0xff,
584 R_41_LCR_BASE+12, 0xff,
585 R_41_LCR_BASE+13, 0xff,
586 R_41_LCR_BASE+14, 0xff,
587 R_41_LCR_BASE+15, 0xff,
588 R_41_LCR_BASE+16, 0xff,
589 R_41_LCR_BASE+17, 0xff,
590 R_41_LCR_BASE+18, 0xff,
591 R_41_LCR_BASE+19, 0xff,
592 R_41_LCR_BASE+20, 0xff,
593 R_41_LCR_BASE+21, 0xff,
594 R_41_LCR_BASE+22, 0xff,
595 R_58_PROGRAM_FRAMING_CODE, 0x40,
596 R_59_H_OFF_FOR_SLICER, 0x47,
597 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
598 R_5D_DID, 0xbd,
599 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800600
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300601 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
602 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800603
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300604 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
605 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
606 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800607 0x00, 0x00
608};
609
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300610static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800611{
612 c ^= (c >> 4);
613 c ^= (c >> 2);
614 c ^= (c >> 1);
615
616 return c & 1;
617}
618
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300619static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800620{
621 static const u8 biphase_tbl[] = {
622 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
623 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
624 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
625 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
626 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
627 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
628 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
629 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
630 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
631 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
632 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
633 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
634 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
635 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
636 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
637 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
638 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
639 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
640 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
641 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
642 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
643 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
644 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
645 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
646 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
647 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
648 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
649 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
650 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
651 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
652 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
653 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
654 };
655 int i;
656 u8 c, err = 0;
657
658 for (i = 0; i < 2 * 13; i += 2) {
659 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
660 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
661 dst[i / 2] = c;
662 }
663 return err & 0xf0;
664}
665
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300666static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800667{
668 static const int wss_bits[8] = {
669 0, 0, 0, 1, 0, 1, 1, 1
670 };
671 unsigned char parity;
672 int wss = 0;
673 int i;
674
675 for (i = 0; i < 16; i++) {
676 int b1 = wss_bits[p[i] & 7];
677 int b2 = wss_bits[(p[i] >> 3) & 7];
678
679 if (b1 == b2)
680 return -1;
681 wss |= b2 << i;
682 }
683 parity = wss & 15;
684 parity ^= parity >> 2;
685 parity ^= parity >> 1;
686
687 if (!(parity & 1))
688 return -1;
689
690 return wss;
691}
692
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300693static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800694{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300695 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200696 u32 acpf;
697 u32 acni;
698 u32 hz;
699 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300700 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800701
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300702 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
703 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
704 return 0;
705
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200706 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200707
708 /* sanity check */
709 if (freq < 32000 || freq > 48000)
710 return -EINVAL;
711
712 /* hz is the refresh rate times 100 */
713 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
714 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
715 acpf = (25600 * freq) / hz;
716 /* acni = (256 * freq * 2^23) / crystal_frequency =
717 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300718 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200719 f = freq;
720 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300721 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200722 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300723 if (state->ucgc) {
724 acpf = acpf * state->cgcdiv / 16;
725 acni = acni * state->cgcdiv / 16;
726 acc = 0x80;
727 if (state->cgcdiv == 3)
728 acc |= 0x40;
729 }
730 if (state->apll)
731 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200732
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300733 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
734 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
735 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300736
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300737 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
738 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300739 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300740 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300741 (acpf >> 16) & 0x03);
742
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300743 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
744 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
745 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800746 state->audclk_freq = freq;
747 return 0;
748}
749
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300750static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800751{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300752 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800753
754 switch (ctrl->id) {
755 case V4L2_CID_BRIGHTNESS:
756 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200757 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800758 return -ERANGE;
759 }
760
761 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300762 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800763 break;
764
765 case V4L2_CID_CONTRAST:
766 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200767 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800768 return -ERANGE;
769 }
770
771 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300772 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800773 break;
774
775 case V4L2_CID_SATURATION:
776 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200777 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800778 return -ERANGE;
779 }
780
781 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300782 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800783 break;
784
785 case V4L2_CID_HUE:
786 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200787 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800788 return -ERANGE;
789 }
790
791 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300792 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800793 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200794
795 default:
796 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800797 }
798
799 return 0;
800}
801
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300802static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800803{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300804 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800805
806 switch (ctrl->id) {
807 case V4L2_CID_BRIGHTNESS:
808 ctrl->value = state->bright;
809 break;
810 case V4L2_CID_CONTRAST:
811 ctrl->value = state->contrast;
812 break;
813 case V4L2_CID_SATURATION:
814 ctrl->value = state->sat;
815 break;
816 case V4L2_CID_HUE:
817 ctrl->value = state->hue;
818 break;
819 default:
820 return -EINVAL;
821 }
822
823 return 0;
824}
825
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300826static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800827{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300828 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800829
Hans Verkuil30b54d52006-01-09 15:25:43 -0200830 /* Prevent unnecessary standard changes. During a standard
831 change the I-Port is temporarily disabled. Any devices
832 reading from that port can get confused.
833 Note that VIDIOC_S_STD is also used to switch from
834 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
835 all I2C devices then you do not want to have an unwanted
836 side-effect here. */
837 if (std == state->std)
838 return;
839
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800840 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
841 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200842 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300843 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800844 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200845 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300846 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800847 }
848
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300849 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300850 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300851 50 Hz / 625 lines 60 Hz / 525 lines
852 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
853 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
854 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
855 011 NTSC N (3.58MHz) PAL M (3.58MHz)
856 100 reserved NTSC-Japan (3.58MHz)
857 */
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -0300858 state->std = std;
859
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300860 if (state->ident == V4L2_IDENT_SAA7111 ||
861 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300862 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300863
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300864 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300865 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300866 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300867 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300868 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300869 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300870 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300871 reg |= 0x40;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300872 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300873 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300874 } else {
875 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300876 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300877
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300878 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300879 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300880 }
881
882 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300883 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300884 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800885}
886
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300887static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800888{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300889 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800890
891 return state->std;
892}
893
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300894static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800895{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300896 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800897 int reg1e, reg1f;
898 int signalOk;
899 int vcr;
900
Hans Verkuilfac9e892006-01-09 15:32:40 -0200901 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300902 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800903 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300904 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800905 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200906 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
907 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800908 return;
909 }
910
911 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300912 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
913 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800914
915 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
916 vcr = !(reg1f & 0x10);
917
Hans Verkuil21fa7152006-01-09 15:25:41 -0200918 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200919 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200920 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200921 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200922 }
Hans Verkuilfac9e892006-01-09 15:32:40 -0200923 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
924 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800925
926 switch (reg1e & 0x03) {
927 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200928 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800929 break;
930 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200931 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800932 break;
933 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200934 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800935 break;
936 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200937 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800938 break;
939 }
940}
941
942/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300943static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800944{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300945 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800946 int is_50hz = (state->std & V4L2_STD_625_50);
947 u8 lcr[24];
948 int i, x;
949
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300950#if 1
951 /* saa7113/7114/7118 VBI support are experimental */
952 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
953 return;
954
955#else
956 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300957 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800958 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300959#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800960
961 for (i = 0; i <= 23; i++)
962 lcr[i] = 0xff;
963
964 if (fmt->service_set == 0) {
965 /* raw VBI */
966 if (is_50hz)
967 for (i = 6; i <= 23; i++)
968 lcr[i] = 0xdd;
969 else
970 for (i = 10; i <= 21; i++)
971 lcr[i] = 0xdd;
972 } else {
973 /* sliced VBI */
974 /* first clear lines that cannot be captured */
975 if (is_50hz) {
976 for (i = 0; i <= 5; i++)
977 fmt->service_lines[0][i] =
978 fmt->service_lines[1][i] = 0;
979 }
980 else {
981 for (i = 0; i <= 9; i++)
982 fmt->service_lines[0][i] =
983 fmt->service_lines[1][i] = 0;
984 for (i = 22; i <= 23; i++)
985 fmt->service_lines[0][i] =
986 fmt->service_lines[1][i] = 0;
987 }
988
989 /* Now set the lcr values according to the specified service */
990 for (i = 6; i <= 23; i++) {
991 lcr[i] = 0;
992 for (x = 0; x <= 1; x++) {
993 switch (fmt->service_lines[1-x][i]) {
994 case 0:
995 lcr[i] |= 0xf << (4 * x);
996 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -0300997 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800998 lcr[i] |= 1 << (4 * x);
999 break;
1000 case V4L2_SLICED_CAPTION_525:
1001 lcr[i] |= 4 << (4 * x);
1002 break;
1003 case V4L2_SLICED_WSS_625:
1004 lcr[i] |= 5 << (4 * x);
1005 break;
1006 case V4L2_SLICED_VPS:
1007 lcr[i] |= 7 << (4 * x);
1008 break;
1009 }
1010 }
1011 }
1012 }
1013
1014 /* write the lcr registers */
1015 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001016 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001017 }
1018
1019 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001020 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001021 saa7115_cfg_vbi_on :
1022 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001023}
1024
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001025static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001026{
1027 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001028 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001029 0, V4L2_SLICED_CAPTION_525, /* 4 */
1030 V4L2_SLICED_WSS_625, 0, /* 5 */
1031 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1032 0, 0, 0, 0
1033 };
1034 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1035 int i;
1036
1037 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1038 return -EINVAL;
1039 memset(sliced, 0, sizeof(*sliced));
1040 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001041 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001042 return 0;
1043 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001044 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001045
1046 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1047 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1048 sliced->service_set |=
1049 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1050 }
1051 return 0;
1052}
1053
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001054static int saa711x_set_size(struct i2c_client *client, int width, int height)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001055{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001056 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001057 int HPSC, HFSC;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001058 int VSCY;
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001059 int res;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001060 int is_50hz = state->std & V4L2_STD_625_50;
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001061 int Vsrc = is_50hz ? 576 : 480+16;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001062
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001063 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
1064
1065 /* FIXME need better bounds checking here */
1066 if ((width < 1) || (width > 1440))
1067 return -EINVAL;
1068 if ((height < 1) || (height > 960))
1069 return -EINVAL;
1070
1071 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
1072 /* Decoder only supports 720 columns and 480 or 576 lines */
1073 if (width != 720)
1074 return -EINVAL;
1075 if (height != Vsrc)
1076 return -EINVAL;
1077 }
1078 if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
1079 return 0;
1080
1081 /* probably have a valid size, let's set it */
1082 /* Set output width/height */
1083 /* width */
1084
1085 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
1086 (u8) (width & 0xff));
1087 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
1088 (u8) ((width >> 8) & 0xff));
1089
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001090 /* Vertical Scaling uses height/2 */
1091 res=height/2;
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001092
1093 /* height */
1094 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
1095 (u8) (res & 0xff));
1096 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehab66440cc2006-08-30 19:52:14 -03001097 (u8) ((res >> 8) & 0xff));
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001098
1099 /* Scaling settings */
1100 /* Hprescaler is floor(inres/outres) */
1101 HPSC = (int)(720 / width);
1102 /* 0 is not allowed (div. by zero) */
1103 HPSC = HPSC ? HPSC : 1;
1104 HFSC = (int)((1024 * 720) / (HPSC * width));
1105 /* FIXME hardcodes to "Task B"
1106 * write H prescaler integer */
1107 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
1108 (u8) (HPSC & 0x3f));
1109
1110 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
1111 /* write H fine-scaling (luminance) */
1112 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
1113 (u8) (HFSC & 0xff));
1114 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
1115 (u8) ((HFSC >> 8) & 0xff));
1116 /* write H fine-scaling (chrominance)
1117 * must be lum/2, so i'll just bitshift :) */
1118 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
1119 (u8) ((HFSC >> 1) & 0xff));
1120 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
1121 (u8) ((HFSC >> 9) & 0xff));
1122
1123 VSCY = (int)((1024 * Vsrc) / height);
1124 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
1125
1126 /* Correct Contrast and Luminance */
1127 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
1128 (u8) (64 * 1024 / VSCY));
1129 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
1130 (u8) (64 * 1024 / VSCY));
1131
1132 /* write V fine-scaling (luminance) */
1133 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
1134 (u8) (VSCY & 0xff));
1135 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
1136 (u8) ((VSCY >> 8) & 0xff));
1137 /* write V fine-scaling (chrominance) */
1138 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
1139 (u8) (VSCY & 0xff));
1140 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
1141 (u8) ((VSCY >> 8) & 0xff));
1142
1143 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
1144
1145 return 0;
1146}
1147
1148static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1149{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001150 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001151 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001152 return 0;
1153 }
1154 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1155 return -EINVAL;
1156
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001157 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001158}
1159
1160/* Decode the sliced VBI data stream as created by the saa7115.
1161 The format is described in the saa7115 datasheet in Tables 25 and 26
1162 and in Figure 33.
1163 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001164 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001165 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001166static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001167 struct v4l2_decode_vbi_line *vbi)
1168{
1169 static const char vbi_no_data_pattern[] = {
1170 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1171 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001172 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001173 u8 *p = vbi->p;
1174 u32 wss;
1175 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1176
1177 vbi->type = 0; /* mark result as a failure */
1178 id1 = p[2];
1179 id2 = p[3];
1180 /* Note: the field bit is inverted for 60 Hz video */
1181 if (state->std & V4L2_STD_525_60)
1182 id1 ^= 0x40;
1183
1184 /* Skip internal header, p now points to the start of the payload */
1185 p += 4;
1186 vbi->p = p;
1187
1188 /* calculate field and line number of the VBI packet (1-23) */
1189 vbi->is_second_field = ((id1 & 0x40) != 0);
1190 vbi->line = (id1 & 0x3f) << 3;
1191 vbi->line |= (id2 & 0x70) >> 4;
1192
1193 /* Obtain data type */
1194 id2 &= 0xf;
1195
1196 /* If the VBI slicer does not detect any signal it will fill up
1197 the payload buffer with 0xa0 bytes. */
1198 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1199 return;
1200
1201 /* decode payloads */
1202 switch (id2) {
1203 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001204 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001205 break;
1206 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001207 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001208 return;
1209 vbi->type = V4L2_SLICED_CAPTION_525;
1210 break;
1211 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001212 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001213 if (wss == -1)
1214 return;
1215 p[0] = wss & 0xff;
1216 p[1] = wss >> 8;
1217 vbi->type = V4L2_SLICED_WSS_625;
1218 break;
1219 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001220 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001221 return;
1222 vbi->type = V4L2_SLICED_VPS;
1223 break;
1224 default:
1225 return;
1226 }
1227}
1228
1229/* ============ SAA7115 AUDIO settings (end) ============= */
1230
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001231static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001232{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001233 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001234 int *iarg = arg;
1235
1236 /* ioctls to allow direct access to the saa7115 registers for testing */
1237 switch (cmd) {
1238 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001239 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001240
1241 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001242 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001243
1244 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001245 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001246
1247 case VIDIOC_G_TUNER:
1248 {
1249 struct v4l2_tuner *vt = arg;
1250 int status;
1251
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001252 if (state->radio)
1253 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001254 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001255
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001256 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001257 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1258 break;
1259 }
1260
1261 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001262 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001263 break;
1264
1265 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001266 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001267
1268 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001269 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001270
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001271 case VIDIOC_QUERYCTRL:
1272 {
1273 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001274
Hans Verkuil18318e02006-06-18 14:49:52 -03001275 switch (qc->id) {
1276 case V4L2_CID_BRIGHTNESS:
1277 case V4L2_CID_CONTRAST:
1278 case V4L2_CID_SATURATION:
1279 case V4L2_CID_HUE:
1280 return v4l2_ctrl_query_fill_std(qc);
1281 default:
1282 return -EINVAL;
1283 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001284 }
1285
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001286 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001287 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001288 break;
1289
1290 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001291 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001292 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001293 break;
1294
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001295 case AUDC_SET_RADIO:
1296 state->radio = 1;
1297 break;
1298
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001299 case VIDIOC_INT_G_VIDEO_ROUTING:
1300 {
1301 struct v4l2_routing *route = arg;
1302
1303 route->input = state->input;
1304 route->output = 0;
1305 break;
1306 }
1307
1308 case VIDIOC_INT_S_VIDEO_ROUTING:
1309 {
1310 struct v4l2_routing *route = arg;
1311
1312 v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
1313 /* saa7113 does not have these inputs */
1314 if (state->ident == V4L2_IDENT_SAA7113 &&
1315 (route->input == SAA7115_COMPOSITE4 ||
1316 route->input == SAA7115_COMPOSITE5)) {
1317 return -EINVAL;
1318 }
1319 if (route->input > SAA7115_SVIDEO3)
1320 return -EINVAL;
1321 if (state->input == route->input)
1322 break;
1323 v4l_dbg(1, debug, client, "now setting %s input\n",
1324 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
1325 state->input = route->input;
1326
1327 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001328 saa711x_write(client, R_02_INPUT_CNTL_1,
1329 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001330 state->input);
1331
1332 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001333 saa711x_write(client, R_09_LUMA_CNTL,
1334 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001335 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1336 break;
1337 }
1338
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001339 case VIDIOC_STREAMON:
1340 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001341 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001342 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1343
1344 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1345 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001346 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001347 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1348 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001349 }
1350 break;
1351
Hans Verkuilb7f82922006-04-02 12:50:42 -03001352 case VIDIOC_INT_S_CRYSTAL_FREQ:
1353 {
1354 struct v4l2_crystal_freq *freq = arg;
1355
1356 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1357 freq->freq != SAA7115_FREQ_24_576_MHZ)
1358 return -EINVAL;
1359 state->crystal_freq = freq->freq;
1360 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1361 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1362 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001363 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001364 break;
1365 }
1366
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001367 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001368 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001369 break;
1370
1371 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001372 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001373 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001374 break;
1375
1376 case VIDIOC_INT_G_VBI_DATA:
1377 {
1378 struct v4l2_sliced_vbi_data *data = arg;
1379
1380 switch (data->id) {
1381 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001382 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001383 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001384 data->data[0] = saa711x_read(client, 0x6c);
1385 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001386 return 0;
1387 case V4L2_SLICED_CAPTION_525:
1388 if (data->field == 0) {
1389 /* CC */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001390 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001391 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001392 data->data[0] = saa711x_read(client, 0x67);
1393 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001394 return 0;
1395 }
1396 /* XDS */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001397 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001398 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001399 data->data[0] = saa711x_read(client, 0x69);
1400 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001401 return 0;
1402 default:
1403 return -EINVAL;
1404 }
1405 break;
1406 }
1407
1408#ifdef CONFIG_VIDEO_ADV_DEBUG
1409 case VIDIOC_INT_G_REGISTER:
1410 {
1411 struct v4l2_register *reg = arg;
1412
1413 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1414 return -EINVAL;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001415 reg->val = saa711x_read(client, reg->reg & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001416 break;
1417 }
1418
1419 case VIDIOC_INT_S_REGISTER:
1420 {
1421 struct v4l2_register *reg = arg;
1422
1423 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1424 return -EINVAL;
1425 if (!capable(CAP_SYS_ADMIN))
1426 return -EPERM;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001427 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001428 break;
1429 }
1430#endif
1431
1432 case VIDIOC_INT_G_CHIP_IDENT:
1433 *iarg = state->ident;
1434 break;
1435
1436 default:
1437 return -EINVAL;
1438 }
1439
1440 return 0;
1441}
1442
1443/* ----------------------------------------------------------------------- */
1444
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001445static struct i2c_driver i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001446
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001447static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001448{
1449 struct i2c_client *client;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001450 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001451 int i;
1452 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001453 u8 chip_id;
1454
1455 /* Check if the adapter supports the needed features */
1456 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1457 return 0;
1458
Panagiotis Issaris74081872006-01-11 19:40:56 -02001459 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001460 if (client == 0)
1461 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001462 client->addr = address;
1463 client->adapter = adapter;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001464 client->driver = &i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001465 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1466
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001467 v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001468
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001469 for (i=0;i<0x0f;i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001470 saa711x_write(client, 0, i);
1471 name[i] = (saa711x_read(client, 0) &0x0f) +'0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001472 if (name[i]>'9')
1473 name[i]+='a'-'9'-1;
1474 }
1475 name[i]='\0';
1476
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001477 saa711x_write(client, 0, 5);
1478 chip_id = saa711x_read(client, 0) & 0x0f;
Hans Verkuil01342352006-03-25 08:19:47 -03001479 if (chip_id < 3 && chip_id > 5) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001480 v4l_dbg(1, debug, client, "saa7115 not found\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001481 kfree(client);
1482 return 0;
1483 }
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001484 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001485 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 -08001486
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001487 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001488 i2c_set_clientdata(client, state);
1489 if (state == NULL) {
1490 kfree(client);
1491 return -ENOMEM;
1492 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001493 state->input = -1;
1494 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001495 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001496 state->bright = 128;
1497 state->contrast = 64;
1498 state->hue = 0;
1499 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001500 switch (chip_id) {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001501 case 1:
1502 state->ident = V4L2_IDENT_SAA7111;
1503 break;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001504 case 3:
1505 state->ident = V4L2_IDENT_SAA7113;
1506 break;
1507 case 4:
1508 state->ident = V4L2_IDENT_SAA7114;
1509 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001510 case 5:
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001511 state->ident = V4L2_IDENT_SAA7115;
1512 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001513 case 8:
1514 state->ident = V4L2_IDENT_SAA7118;
1515 break;
1516 default:
1517 state->ident = V4L2_IDENT_SAA7111;
1518 v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
1519
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001520 }
1521
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001522 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001523
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001524 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001525
1526 /* init to 60hz/48khz */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001527 if (state->ident == V4L2_IDENT_SAA7111 ||
1528 state->ident == V4L2_IDENT_SAA7113) {
Hans Verkuilb7f82922006-04-02 12:50:42 -03001529 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001530 saa711x_writeregs(client, saa7113_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001531 } else {
1532 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001533 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001534 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001535 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001536 state->std = V4L2_STD_NTSC;
1537 saa711x_set_size(client, 720, 480);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001538 saa711x_writeregs(client, saa7115_cfg_60hz_video);
1539 saa711x_set_audio_clock_freq(client, state->audclk_freq);
1540 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001541
1542 i2c_attach_client(client);
1543
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001544 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001545 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 -08001546
1547 return 0;
1548}
1549
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001550static int saa711x_probe(struct i2c_adapter *adapter)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001551{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001552 if (adapter->class & I2C_CLASS_TV_ANALOG)
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001553 return i2c_probe(adapter, &addr_data, &saa711x_attach);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001554 return 0;
1555}
1556
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001557static int saa711x_detach(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001558{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001559 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001560 int err;
1561
1562 err = i2c_detach_client(client);
1563 if (err) {
1564 return err;
1565 }
1566
1567 kfree(state);
1568 kfree(client);
1569 return 0;
1570}
1571
1572/* ----------------------------------------------------------------------- */
1573
1574/* i2c implementation */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001575static struct i2c_driver i2c_driver_saa711x = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001576 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001577 .name = "saa7115",
1578 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001579 .id = I2C_DRIVERID_SAA711X,
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001580 .attach_adapter = saa711x_probe,
1581 .detach_client = saa711x_detach,
1582 .command = saa711x_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001583};
1584
1585
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001586static int __init saa711x_init_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001587{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001588 return i2c_add_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001589}
1590
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001591static void __exit saa711x_cleanup_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001592{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001593 i2c_del_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001594}
1595
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001596module_init(saa711x_init_module);
1597module_exit(saa711x_cleanup_module);