blob: 4d5bbd859de1d6e13cf8f3226291594f0594afa9 [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 Chehab97d9e802006-09-03 09:38:11 -030051#define VRES_60HZ (480+16)
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030052
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030053MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030054MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
55 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080056MODULE_LICENSE("GPL");
57
58static int debug = 0;
Hans Verkuilfac9e892006-01-09 15:32:40 -020059module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080060
61MODULE_PARM_DESC(debug, "Debug level (0-1)");
62
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030063static unsigned short normal_i2c[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030064 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
65 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030066 I2C_CLIENT_END };
Hans Verkuile19b2fc2005-11-13 16:08:04 -080067
68
69I2C_CLIENT_INSMOD;
70
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030071struct saa711x_state {
Hans Verkuile19b2fc2005-11-13 16:08:04 -080072 v4l2_std_id std;
73 int input;
Marco Schluessler4cbca182007-01-21 19:43:38 -030074 int output;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080075 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020076 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080077 int bright;
78 int contrast;
79 int hue;
80 int sat;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030081 int width;
82 int height;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080083 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020084 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030085 u32 crystal_freq;
86 u8 ucgc;
87 u8 cgcdiv;
88 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080089};
90
91/* ----------------------------------------------------------------------- */
92
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030093static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080094{
95 return i2c_smbus_write_byte_data(client, reg, value);
96}
97
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030098/* Sanity routine to check if a register is present */
99static int saa711x_has_reg(const int id, const u8 reg)
100{
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300101 if (id == V4L2_IDENT_SAA7111)
102 return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
103 (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300104
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300105 /* common for saa7113/4/5/8 */
106 if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
107 reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
108 reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
109 reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300110 return 0;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300111
112 switch (id) {
113 case V4L2_IDENT_SAA7113:
114 return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
115 reg != 0x5d && reg < 0x63;
116 case V4L2_IDENT_SAA7114:
117 return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
118 (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
119 reg != 0x81 && reg < 0xf0;
120 case V4L2_IDENT_SAA7115:
121 return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
122 case V4L2_IDENT_SAA7118:
123 return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
124 (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
125 (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
126 }
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300127 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;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300144 } else {
145 v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300146 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800147 }
148 return 0;
149}
150
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300151static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800152{
153 return i2c_smbus_read_byte_data(client, reg);
154}
155
156/* ----------------------------------------------------------------------- */
157
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300158/* SAA7111 initialization table */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300159static const unsigned char saa7111_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300160 R_01_INC_DELAY, 0x00, /* reserved */
161
162 /*front end */
163 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
164 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
165 * GAFIX=0, GAI1=256, GAI2=256 */
166 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
167 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
168
169 /* decoder */
170 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
171 * pixels after end of last line */
172 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
173 * work with NTSC, too */
174 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
175 * VTRC=1, HPLL=0, VNOI=0 */
176 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
177 * VBLB=0, UPTCV=0, APER=1 */
178 R_0A_LUMA_BRIGHT_CNTL, 0x80,
179 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
180 R_0C_CHROMA_SAT_CNTL, 0x40,
181 R_0D_CHROMA_HUE_CNTL, 0x00,
182 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
183 * FCTC=0, CHBW=1 */
184 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
185 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
186 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
187 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
188 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
189 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
190 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
191 R_15_VGATE_START_FID_CHG, 0x00,
192 R_16_VGATE_STOP, 0x00,
193 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
194
195 0x00, 0x00
196};
197
198/* SAA7113 init codes */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300199static const unsigned char saa7113_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300200 R_01_INC_DELAY, 0x08,
201 R_02_INPUT_CNTL_1, 0xc2,
202 R_03_INPUT_CNTL_2, 0x30,
203 R_04_INPUT_CNTL_3, 0x00,
204 R_05_INPUT_CNTL_4, 0x00,
205 R_06_H_SYNC_START, 0x89,
206 R_07_H_SYNC_STOP, 0x0d,
207 R_08_SYNC_CNTL, 0x88,
208 R_09_LUMA_CNTL, 0x01,
209 R_0A_LUMA_BRIGHT_CNTL, 0x80,
210 R_0B_LUMA_CONTRAST_CNTL, 0x47,
211 R_0C_CHROMA_SAT_CNTL, 0x40,
212 R_0D_CHROMA_HUE_CNTL, 0x00,
213 R_0E_CHROMA_CNTL_1, 0x01,
214 R_0F_CHROMA_GAIN_CNTL, 0x2a,
215 R_10_CHROMA_CNTL_2, 0x08,
216 R_11_MODE_DELAY_CNTL, 0x0c,
217 R_12_RT_SIGNAL_CNTL, 0x07,
218 R_13_RT_X_PORT_OUT_CNTL, 0x00,
219 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
220 R_15_VGATE_START_FID_CHG, 0x00,
221 R_16_VGATE_STOP, 0x00,
222 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
223
224 0x00, 0x00
225};
226
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800227/* If a value differs from the Hauppauge driver values, then the comment starts with
228 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
229 Hauppauge driver sets. */
230
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300231/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800232static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300233 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300234 R_01_INC_DELAY, 0x48, /* white peak control disabled */
235 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
236 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
237 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300238 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300239 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
240 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300241 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300242 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
243 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
244 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
245 R_0D_CHROMA_HUE_CNTL, 0x00,
246 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
247 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
248 R_11_MODE_DELAY_CNTL, 0x00,
249 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
250 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
251 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
252 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
253 R_19_RAW_DATA_OFF_CNTL, 0x80,
254 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
255 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
256 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
257 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300258
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300259
260 R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
261
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300262 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300263 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
264 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800265 0x00, 0x00
266};
267
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300268/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800269static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300270 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
271 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
272 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
273 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800274 0x00, 0x00
275};
276
277/* ============== SAA7715 VIDEO templates ============= */
278
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800279static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300280 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
281 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800282
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300283 R_15_VGATE_START_FID_CHG, 0x03,
284 R_16_VGATE_STOP, 0x11,
285 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800286
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300287 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
288 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800289
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300290 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800291
292 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300293 R_90_A_TASK_HANDLING_CNTL, 0x80,
294 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
295 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
296 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
297
298 /* hoffset low (input), 0x0002 is minimum */
299 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
300 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
301
302 /* hsize low (input), 0x02d0 = 720 */
303 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
304 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
305
306 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
307 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
308
309 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
310 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
311
312 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
313 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
314
315 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
316 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800317
318 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300319 R_C0_B_TASK_HANDLING_CNTL, 0x00,
320 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
321 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
322 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800323
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300324 /* 0x0002 is minimum */
325 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
326 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800327
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300328 /* 0x02d0 = 720 */
329 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
330 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
331
332 /* vwindow start 0x12 = 18 */
333 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
334 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
335
336 /* vwindow length 0xf8 = 248 */
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -0300337 R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
338 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300339
340 /* hwindow 0x02d0 = 720 */
341 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
342 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
343
344 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
345 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
346 R_F5_PULSGEN_LINE_LENGTH, 0xad,
347 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
348
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800349 0x00, 0x00
350};
351
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800352static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300353 R_80_GLOBAL_CNTL_1, 0x00,
354 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800355
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300356 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
357 R_16_VGATE_STOP, 0x16,
358 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800359
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300360 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
361 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800362
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300363 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800364
365 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300366 R_90_A_TASK_HANDLING_CNTL, 0x81,
367 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
368 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
369 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
370
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800371 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
372 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300373 /* hoffset low (input), 0x0002 is minimum */
374 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
375 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
376
377 /* hsize low (input), 0x02d0 = 720 */
378 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
379 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
380
381 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
382 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
383
384 /* vsize 0x12 = 18 */
385 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
386 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
387
388 /* hsize 0x05a0 = 1440 */
389 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
390 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
391 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
392 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800393
394 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300395 R_C0_B_TASK_HANDLING_CNTL, 0x00,
396 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
397 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
398 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800399
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300400 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
401 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
402 /* hoffset low (input), 0x0002 is minimum. See comment above. */
403 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
404 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800405
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300406 /* hsize 0x02d0 = 720 */
407 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
408 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
409
410 /* voffset 0x16 = 22 */
411 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
412 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
413
414 /* vsize 0x0120 = 288 */
415 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
416 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
417
418 /* hsize 0x02d0 = 720 */
419 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
420 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
421
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300422 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
423 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
424 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
425 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
426
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800427 0x00, 0x00
428};
429
430/* ============== SAA7715 VIDEO templates (end) ======= */
431
432static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300433 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
434 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
435 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
436 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
437 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
438
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800439 0x00, 0x00
440};
441
442static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300443 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
444 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
445 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
446 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
447 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
448
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800449 0x00, 0x00
450};
451
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300452
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800453static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300454 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300455 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
456 R_84_I_PORT_SIGNAL_DEF, 0x20,
457 R_85_I_PORT_SIGNAL_POLAR, 0x21,
458 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
459 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800460
461 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300462 R_A0_A_HORIZ_PRESCALING, 0x01,
463 R_A1_A_ACCUMULATION_LENGTH, 0x00,
464 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800465
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300466 /* Configure controls at nominal value*/
467 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
468 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
469 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
470
471 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
472 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
473 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
474
475 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
476
477 /* must be horiz lum scaling / 2 */
478 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
479 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
480
481 /* must be offset luma / 2 */
482 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
483
484 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
485 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
486
487 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
488 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
489
490 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
491
492 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
493 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
494 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
495 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
496
497 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
498 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
499 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
500 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800501
502 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300503 R_D0_B_HORIZ_PRESCALING, 0x01,
504 R_D1_B_ACCUMULATION_LENGTH, 0x00,
505 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800506
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300507 /* Configure controls at nominal value*/
508 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
509 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
510 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800511
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300512 /* hor lum scaling 0x0400 = 1 */
513 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
514 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
515
516 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
517
518 /* must be hor lum scaling / 2 */
519 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
520 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
521
522 /* must be offset luma / 2 */
523 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
524
525 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
526 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
527
528 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
529 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
530
531 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
532
533 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
534 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
535 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
536 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
537
538 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
539 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
540 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
541 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
542
543 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
544 R_F3_PLL_INCREMENT, 0x46,
545 R_F4_PLL2_STATUS, 0x00,
546 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
547 R_F8_PULSE_B_POS, 0x00,
548 R_F9_PULSE_B_POS_MSB, 0x4b,
549 R_FA_PULSE_C_POS, 0x00,
550 R_FB_PULSE_C_POS_MSB, 0x4b,
551
552 /* PLL2 lock detection settings: 71 lines 50% phase error */
553 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800554
555 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300556 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
557 R_41_LCR_BASE, 0xff,
558 R_41_LCR_BASE+1, 0xff,
559 R_41_LCR_BASE+2, 0xff,
560 R_41_LCR_BASE+3, 0xff,
561 R_41_LCR_BASE+4, 0xff,
562 R_41_LCR_BASE+5, 0xff,
563 R_41_LCR_BASE+6, 0xff,
564 R_41_LCR_BASE+7, 0xff,
565 R_41_LCR_BASE+8, 0xff,
566 R_41_LCR_BASE+9, 0xff,
567 R_41_LCR_BASE+10, 0xff,
568 R_41_LCR_BASE+11, 0xff,
569 R_41_LCR_BASE+12, 0xff,
570 R_41_LCR_BASE+13, 0xff,
571 R_41_LCR_BASE+14, 0xff,
572 R_41_LCR_BASE+15, 0xff,
573 R_41_LCR_BASE+16, 0xff,
574 R_41_LCR_BASE+17, 0xff,
575 R_41_LCR_BASE+18, 0xff,
576 R_41_LCR_BASE+19, 0xff,
577 R_41_LCR_BASE+20, 0xff,
578 R_41_LCR_BASE+21, 0xff,
579 R_41_LCR_BASE+22, 0xff,
580 R_58_PROGRAM_FRAMING_CODE, 0x40,
581 R_59_H_OFF_FOR_SLICER, 0x47,
582 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
583 R_5D_DID, 0xbd,
584 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800585
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300586 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800587
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300588 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
589 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
590 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800591 0x00, 0x00
592};
593
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300594static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800595{
596 c ^= (c >> 4);
597 c ^= (c >> 2);
598 c ^= (c >> 1);
599
600 return c & 1;
601}
602
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300603static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800604{
605 static const u8 biphase_tbl[] = {
606 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
607 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
608 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
609 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
610 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
611 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
612 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
613 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
614 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
615 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
616 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
617 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
618 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
619 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
620 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
621 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
622 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
623 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
624 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
625 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
626 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
627 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
628 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
629 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
630 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
631 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
632 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
633 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
634 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
635 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
636 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
637 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
638 };
639 int i;
640 u8 c, err = 0;
641
642 for (i = 0; i < 2 * 13; i += 2) {
643 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
644 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
645 dst[i / 2] = c;
646 }
647 return err & 0xf0;
648}
649
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300650static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800651{
652 static const int wss_bits[8] = {
653 0, 0, 0, 1, 0, 1, 1, 1
654 };
655 unsigned char parity;
656 int wss = 0;
657 int i;
658
659 for (i = 0; i < 16; i++) {
660 int b1 = wss_bits[p[i] & 7];
661 int b2 = wss_bits[(p[i] >> 3) & 7];
662
663 if (b1 == b2)
664 return -1;
665 wss |= b2 << i;
666 }
667 parity = wss & 15;
668 parity ^= parity >> 2;
669 parity ^= parity >> 1;
670
671 if (!(parity & 1))
672 return -1;
673
674 return wss;
675}
676
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300677static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800678{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300679 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200680 u32 acpf;
681 u32 acni;
682 u32 hz;
683 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300684 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800685
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300686 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
687 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
688 return 0;
689
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200690 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200691
692 /* sanity check */
693 if (freq < 32000 || freq > 48000)
694 return -EINVAL;
695
696 /* hz is the refresh rate times 100 */
697 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
698 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
699 acpf = (25600 * freq) / hz;
700 /* acni = (256 * freq * 2^23) / crystal_frequency =
701 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300702 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200703 f = freq;
704 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300705 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200706 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300707 if (state->ucgc) {
708 acpf = acpf * state->cgcdiv / 16;
709 acni = acni * state->cgcdiv / 16;
710 acc = 0x80;
711 if (state->cgcdiv == 3)
712 acc |= 0x40;
713 }
714 if (state->apll)
715 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200716
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300717 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
718 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
719 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300720
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300721 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
722 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300723 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300724 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300725 (acpf >> 16) & 0x03);
726
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300727 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
728 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
729 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800730 state->audclk_freq = freq;
731 return 0;
732}
733
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300734static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800735{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300736 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800737
738 switch (ctrl->id) {
739 case V4L2_CID_BRIGHTNESS:
740 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200741 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800742 return -ERANGE;
743 }
744
745 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300746 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800747 break;
748
749 case V4L2_CID_CONTRAST:
750 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200751 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800752 return -ERANGE;
753 }
754
755 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300756 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800757 break;
758
759 case V4L2_CID_SATURATION:
760 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200761 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800762 return -ERANGE;
763 }
764
765 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300766 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800767 break;
768
769 case V4L2_CID_HUE:
770 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200771 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800772 return -ERANGE;
773 }
774
775 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300776 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800777 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200778
779 default:
780 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800781 }
782
783 return 0;
784}
785
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300786static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800787{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300788 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800789
790 switch (ctrl->id) {
791 case V4L2_CID_BRIGHTNESS:
792 ctrl->value = state->bright;
793 break;
794 case V4L2_CID_CONTRAST:
795 ctrl->value = state->contrast;
796 break;
797 case V4L2_CID_SATURATION:
798 ctrl->value = state->sat;
799 break;
800 case V4L2_CID_HUE:
801 ctrl->value = state->hue;
802 break;
803 default:
804 return -EINVAL;
805 }
806
807 return 0;
808}
809
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300810static int saa711x_set_size(struct i2c_client *client, int width, int height)
811{
812 struct saa711x_state *state = i2c_get_clientdata(client);
813 int HPSC, HFSC;
814 int VSCY;
815 int res;
816 int is_50hz = state->std & V4L2_STD_625_50;
817 int Vsrc = is_50hz ? 576 : 480;
818
819 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
820
821 /* FIXME need better bounds checking here */
822 if ((width < 1) || (width > 1440))
823 return -EINVAL;
824 if ((height < 1) || (height > Vsrc))
825 return -EINVAL;
826
827 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
828 /* Decoder only supports 720 columns and 480 or 576 lines */
829 if (width != 720)
830 return -EINVAL;
831 if (height != Vsrc)
832 return -EINVAL;
833 }
834
835 state->width = width;
836 state->height = height;
837
838 if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
839 return 0;
840
841 /* probably have a valid size, let's set it */
842 /* Set output width/height */
843 /* width */
844
845 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
846 (u8) (width & 0xff));
847 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
848 (u8) ((width >> 8) & 0xff));
849
850 /* Vertical Scaling uses height/2 */
851 res=height/2;
852
853 /* On 60Hz, it is using a higher Vertical Output Size */
854 if (!is_50hz)
Hans Verkuild0d30c02006-11-25 09:45:50 -0300855 res += (VRES_60HZ - 480) >> 1;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300856
857 /* height */
858 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
859 (u8) (res & 0xff));
860 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
861 (u8) ((res >> 8) & 0xff));
862
863 /* Scaling settings */
864 /* Hprescaler is floor(inres/outres) */
865 HPSC = (int)(720 / width);
866 /* 0 is not allowed (div. by zero) */
867 HPSC = HPSC ? HPSC : 1;
868 HFSC = (int)((1024 * 720) / (HPSC * width));
869 /* FIXME hardcodes to "Task B"
870 * write H prescaler integer */
871 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
872 (u8) (HPSC & 0x3f));
873
874 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
875 /* write H fine-scaling (luminance) */
876 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
877 (u8) (HFSC & 0xff));
878 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
879 (u8) ((HFSC >> 8) & 0xff));
880 /* write H fine-scaling (chrominance)
881 * must be lum/2, so i'll just bitshift :) */
882 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
883 (u8) ((HFSC >> 1) & 0xff));
884 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
885 (u8) ((HFSC >> 9) & 0xff));
886
887 VSCY = (int)((1024 * Vsrc) / height);
888 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
889
890 /* Correct Contrast and Luminance */
891 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
892 (u8) (64 * 1024 / VSCY));
893 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
894 (u8) (64 * 1024 / VSCY));
895
896 /* write V fine-scaling (luminance) */
897 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
898 (u8) (VSCY & 0xff));
899 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
900 (u8) ((VSCY >> 8) & 0xff));
901 /* write V fine-scaling (chrominance) */
902 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
903 (u8) (VSCY & 0xff));
904 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
905 (u8) ((VSCY >> 8) & 0xff));
906
907 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
908
909 /* Activates task "B" */
910 saa711x_write(client, R_80_GLOBAL_CNTL_1,
Hans Verkuild0d30c02006-11-25 09:45:50 -0300911 saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300912
913 return 0;
914}
915
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300916static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800917{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300918 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800919
Hans Verkuil30b54d52006-01-09 15:25:43 -0200920 /* Prevent unnecessary standard changes. During a standard
921 change the I-Port is temporarily disabled. Any devices
922 reading from that port can get confused.
923 Note that VIDIOC_S_STD is also used to switch from
924 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
925 all I2C devices then you do not want to have an unwanted
926 side-effect here. */
927 if (std == state->std)
928 return;
929
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300930 state->std = std;
931
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800932 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
933 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200934 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300935 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300936 saa711x_set_size(client, 720, 480);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800937 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200938 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300939 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300940 saa711x_set_size(client, 720, 576);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800941 }
942
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300943 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300944 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300945 50 Hz / 625 lines 60 Hz / 525 lines
946 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
947 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
948 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
949 011 NTSC N (3.58MHz) PAL M (3.58MHz)
950 100 reserved NTSC-Japan (3.58MHz)
951 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300952 if (state->ident == V4L2_IDENT_SAA7111 ||
953 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300954 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300955
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300956 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300957 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300958 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300959 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300960 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300961 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300962 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300963 reg |= 0x40;
Mauro Carvalho Chehaba9aaec42007-03-13 13:41:49 -0300964 } else if (std & V4L2_STD_SECAM) {
Pádraig Bradyfc2fa312006-10-09 08:02:17 -0300965 reg |= 0x50;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300966 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300967 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300968 } else {
969 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300970 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300971
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300972 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300973 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300974 }
975
976 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300977 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300978 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800979}
980
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300981static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800982{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300983 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800984
985 return state->std;
986}
987
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300988static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800989{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300990 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800991 int reg1e, reg1f;
992 int signalOk;
993 int vcr;
994
Hans Verkuilfac9e892006-01-09 15:32:40 -0200995 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300996 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800997 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300998 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800999 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -02001000 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
1001 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001002 return;
1003 }
1004
1005 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001006 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
1007 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001008
1009 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1010 vcr = !(reg1f & 0x10);
1011
Hans Verkuil21fa7152006-01-09 15:25:41 -02001012 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001013 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001014 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001015 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001016 }
Hans Verkuilfac9e892006-01-09 15:32:40 -02001017 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1018 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001019
1020 switch (reg1e & 0x03) {
1021 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001022 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001023 break;
1024 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001025 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001026 break;
1027 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001028 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001029 break;
1030 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001031 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001032 break;
1033 }
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001034 v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001035}
1036
1037/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001038static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001039{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001040 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001041 int is_50hz = (state->std & V4L2_STD_625_50);
1042 u8 lcr[24];
1043 int i, x;
1044
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001045#if 1
1046 /* saa7113/7114/7118 VBI support are experimental */
1047 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
1048 return;
1049
1050#else
1051 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001052 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001053 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001054#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001055
1056 for (i = 0; i <= 23; i++)
1057 lcr[i] = 0xff;
1058
1059 if (fmt->service_set == 0) {
1060 /* raw VBI */
1061 if (is_50hz)
1062 for (i = 6; i <= 23; i++)
1063 lcr[i] = 0xdd;
1064 else
1065 for (i = 10; i <= 21; i++)
1066 lcr[i] = 0xdd;
1067 } else {
1068 /* sliced VBI */
1069 /* first clear lines that cannot be captured */
1070 if (is_50hz) {
1071 for (i = 0; i <= 5; i++)
1072 fmt->service_lines[0][i] =
1073 fmt->service_lines[1][i] = 0;
1074 }
1075 else {
1076 for (i = 0; i <= 9; i++)
1077 fmt->service_lines[0][i] =
1078 fmt->service_lines[1][i] = 0;
1079 for (i = 22; i <= 23; i++)
1080 fmt->service_lines[0][i] =
1081 fmt->service_lines[1][i] = 0;
1082 }
1083
1084 /* Now set the lcr values according to the specified service */
1085 for (i = 6; i <= 23; i++) {
1086 lcr[i] = 0;
1087 for (x = 0; x <= 1; x++) {
1088 switch (fmt->service_lines[1-x][i]) {
1089 case 0:
1090 lcr[i] |= 0xf << (4 * x);
1091 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001092 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001093 lcr[i] |= 1 << (4 * x);
1094 break;
1095 case V4L2_SLICED_CAPTION_525:
1096 lcr[i] |= 4 << (4 * x);
1097 break;
1098 case V4L2_SLICED_WSS_625:
1099 lcr[i] |= 5 << (4 * x);
1100 break;
1101 case V4L2_SLICED_VPS:
1102 lcr[i] |= 7 << (4 * x);
1103 break;
1104 }
1105 }
1106 }
1107 }
1108
1109 /* write the lcr registers */
1110 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001111 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001112 }
1113
1114 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001115 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001116 saa7115_cfg_vbi_on :
1117 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001118}
1119
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001120static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001121{
1122 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001123 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001124 0, V4L2_SLICED_CAPTION_525, /* 4 */
1125 V4L2_SLICED_WSS_625, 0, /* 5 */
1126 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1127 0, 0, 0, 0
1128 };
1129 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1130 int i;
1131
1132 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1133 return -EINVAL;
1134 memset(sliced, 0, sizeof(*sliced));
1135 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001136 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001137 return 0;
1138 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001139 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001140
1141 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1142 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1143 sliced->service_set |=
1144 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1145 }
1146 return 0;
1147}
1148
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001149static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1150{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001151 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001152 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001153 return 0;
1154 }
1155 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1156 return -EINVAL;
1157
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001158 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001159}
1160
1161/* Decode the sliced VBI data stream as created by the saa7115.
1162 The format is described in the saa7115 datasheet in Tables 25 and 26
1163 and in Figure 33.
1164 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001165 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001166 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001167static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168 struct v4l2_decode_vbi_line *vbi)
1169{
1170 static const char vbi_no_data_pattern[] = {
1171 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1172 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001173 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001174 u8 *p = vbi->p;
1175 u32 wss;
1176 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1177
1178 vbi->type = 0; /* mark result as a failure */
1179 id1 = p[2];
1180 id2 = p[3];
1181 /* Note: the field bit is inverted for 60 Hz video */
1182 if (state->std & V4L2_STD_525_60)
1183 id1 ^= 0x40;
1184
1185 /* Skip internal header, p now points to the start of the payload */
1186 p += 4;
1187 vbi->p = p;
1188
1189 /* calculate field and line number of the VBI packet (1-23) */
1190 vbi->is_second_field = ((id1 & 0x40) != 0);
1191 vbi->line = (id1 & 0x3f) << 3;
1192 vbi->line |= (id2 & 0x70) >> 4;
1193
1194 /* Obtain data type */
1195 id2 &= 0xf;
1196
1197 /* If the VBI slicer does not detect any signal it will fill up
1198 the payload buffer with 0xa0 bytes. */
1199 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1200 return;
1201
1202 /* decode payloads */
1203 switch (id2) {
1204 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001205 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001206 break;
1207 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001208 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001209 return;
1210 vbi->type = V4L2_SLICED_CAPTION_525;
1211 break;
1212 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001213 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001214 if (wss == -1)
1215 return;
1216 p[0] = wss & 0xff;
1217 p[1] = wss >> 8;
1218 vbi->type = V4L2_SLICED_WSS_625;
1219 break;
1220 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001221 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001222 return;
1223 vbi->type = V4L2_SLICED_VPS;
1224 break;
1225 default:
1226 return;
1227 }
1228}
1229
1230/* ============ SAA7115 AUDIO settings (end) ============= */
1231
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001232static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001233{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001234 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001235 int *iarg = arg;
1236
1237 /* ioctls to allow direct access to the saa7115 registers for testing */
1238 switch (cmd) {
1239 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001240 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001241
1242 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001243 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001244
1245 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001246 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001247
1248 case VIDIOC_G_TUNER:
1249 {
1250 struct v4l2_tuner *vt = arg;
1251 int status;
1252
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001253 if (state->radio)
1254 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001255 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001256
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001257 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001258 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1259 break;
1260 }
1261
1262 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001263 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001264 break;
1265
1266 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001267 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001268
1269 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001270 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001271
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001272 case VIDIOC_QUERYCTRL:
1273 {
1274 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001275
Hans Verkuil18318e02006-06-18 14:49:52 -03001276 switch (qc->id) {
1277 case V4L2_CID_BRIGHTNESS:
1278 case V4L2_CID_CONTRAST:
1279 case V4L2_CID_SATURATION:
1280 case V4L2_CID_HUE:
1281 return v4l2_ctrl_query_fill_std(qc);
1282 default:
1283 return -EINVAL;
1284 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001285 }
1286
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001287 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001288 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001289 break;
1290
1291 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001292 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001293 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001294 break;
1295
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001296 case AUDC_SET_RADIO:
1297 state->radio = 1;
1298 break;
1299
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001300 case VIDIOC_INT_G_VIDEO_ROUTING:
1301 {
1302 struct v4l2_routing *route = arg;
1303
1304 route->input = state->input;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001305 route->output = state->output;
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001306 break;
1307 }
1308
1309 case VIDIOC_INT_S_VIDEO_ROUTING:
1310 {
1311 struct v4l2_routing *route = arg;
1312
Marco Schluessler4cbca182007-01-21 19:43:38 -03001313 v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001314 /* saa7113 does not have these inputs */
1315 if (state->ident == V4L2_IDENT_SAA7113 &&
1316 (route->input == SAA7115_COMPOSITE4 ||
1317 route->input == SAA7115_COMPOSITE5)) {
1318 return -EINVAL;
1319 }
1320 if (route->input > SAA7115_SVIDEO3)
1321 return -EINVAL;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001322 if (route->output > SAA7115_IPORT_ON)
1323 return -EINVAL;
1324 if (state->input == route->input && state->output == route->output)
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001325 break;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001326 v4l_dbg(1, debug, client, "now setting %s input %s output\n",
1327 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001328 state->input = route->input;
1329
1330 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001331 saa711x_write(client, R_02_INPUT_CNTL_1,
1332 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001333 state->input);
1334
1335 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001336 saa711x_write(client, R_09_LUMA_CNTL,
1337 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001338 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
Marco Schluessler4cbca182007-01-21 19:43:38 -03001339
1340 state->output = route->output;
1341 if (state->ident == V4L2_IDENT_SAA7114 ||
1342 state->ident == V4L2_IDENT_SAA7115) {
1343 saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
1344 (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
1345 (state->output & 0x01));
1346 }
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001347 break;
1348 }
1349
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001350 case VIDIOC_STREAMON:
1351 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001352 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001353 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1354
1355 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1356 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001357 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001358 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1359 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001360 }
1361 break;
1362
Hans Verkuilb7f82922006-04-02 12:50:42 -03001363 case VIDIOC_INT_S_CRYSTAL_FREQ:
1364 {
1365 struct v4l2_crystal_freq *freq = arg;
1366
1367 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1368 freq->freq != SAA7115_FREQ_24_576_MHZ)
1369 return -EINVAL;
1370 state->crystal_freq = freq->freq;
1371 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1372 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1373 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001374 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001375 break;
1376 }
1377
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001378 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001379 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001380 break;
1381
1382 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001383 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001384 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001385 break;
1386
1387 case VIDIOC_INT_G_VBI_DATA:
1388 {
1389 struct v4l2_sliced_vbi_data *data = arg;
1390
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001391 /* Note: the internal field ID is inverted for NTSC,
1392 so data->field 0 maps to the saa7115 even field,
1393 whereas for PAL it maps to the saa7115 odd field. */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001394 switch (data->id) {
1395 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001396 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001397 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001398 data->data[0] = saa711x_read(client, 0x6c);
1399 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001400 return 0;
1401 case V4L2_SLICED_CAPTION_525:
1402 if (data->field == 0) {
1403 /* CC */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001404 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001405 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001406 data->data[0] = saa711x_read(client, 0x69);
1407 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001408 return 0;
1409 }
1410 /* XDS */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001411 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001412 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001413 data->data[0] = saa711x_read(client, 0x67);
1414 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001415 return 0;
1416 default:
1417 return -EINVAL;
1418 }
1419 break;
1420 }
1421
1422#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001423 case VIDIOC_DBG_G_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -03001424 case VIDIOC_DBG_S_REGISTER:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001425 {
1426 struct v4l2_register *reg = arg;
1427
Hans Verkuilf3d092b2007-02-23 20:55:14 -03001428 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001429 return -EINVAL;
1430 if (!capable(CAP_SYS_ADMIN))
1431 return -EPERM;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001432 if (cmd == VIDIOC_DBG_G_REGISTER)
1433 reg->val = saa711x_read(client, reg->reg & 0xff);
1434 else
1435 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001436 break;
1437 }
1438#endif
1439
1440 case VIDIOC_INT_G_CHIP_IDENT:
1441 *iarg = state->ident;
1442 break;
1443
1444 default:
1445 return -EINVAL;
1446 }
1447
1448 return 0;
1449}
1450
1451/* ----------------------------------------------------------------------- */
1452
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001453static struct i2c_driver i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001454
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001455static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001456{
1457 struct i2c_client *client;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001458 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001459 int i;
1460 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001461 u8 chip_id;
1462
1463 /* Check if the adapter supports the needed features */
1464 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1465 return 0;
1466
Panagiotis Issaris74081872006-01-11 19:40:56 -02001467 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001468 if (client == 0)
1469 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001470 client->addr = address;
1471 client->adapter = adapter;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001472 client->driver = &i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001473 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1474
Hans Verkuild0d30c02006-11-25 09:45:50 -03001475 for (i = 0; i < 0x0f; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001476 saa711x_write(client, 0, i);
Hans Verkuild0d30c02006-11-25 09:45:50 -03001477 name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
1478 if (name[i] > '9')
1479 name[i] += 'a' - '9' - 1;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001480 }
Hans Verkuild0d30c02006-11-25 09:45:50 -03001481 name[i] = '\0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001482
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001483 saa711x_write(client, 0, 5);
1484 chip_id = saa711x_read(client, 0) & 0x0f;
Mauro Carvalho Chehab3e7d3e52006-09-01 18:39:05 -03001485
Hans Verkuilf7668162006-11-25 09:40:28 -03001486 /* Check whether this chip is part of the saa711x series */
1487 if (memcmp(name, "1f711", 5)) {
1488 v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
1489 address << 1, name);
1490 return 0;
1491 }
1492
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001493 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001494 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 -08001495
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001496 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001497 i2c_set_clientdata(client, state);
1498 if (state == NULL) {
1499 kfree(client);
1500 return -ENOMEM;
1501 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001502 state->input = -1;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001503 state->output = SAA7115_IPORT_ON;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001504 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001505 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001506 state->bright = 128;
1507 state->contrast = 64;
1508 state->hue = 0;
1509 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001510 switch (chip_id) {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001511 case 1:
1512 state->ident = V4L2_IDENT_SAA7111;
1513 break;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001514 case 3:
1515 state->ident = V4L2_IDENT_SAA7113;
1516 break;
1517 case 4:
1518 state->ident = V4L2_IDENT_SAA7114;
1519 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001520 case 5:
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001521 state->ident = V4L2_IDENT_SAA7115;
1522 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001523 case 8:
1524 state->ident = V4L2_IDENT_SAA7118;
1525 break;
1526 default:
1527 state->ident = V4L2_IDENT_SAA7111;
1528 v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
1529
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001530 }
1531
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001532 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001533
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001534 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001535
1536 /* init to 60hz/48khz */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001537 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
1538 switch (state->ident) {
1539 case V4L2_IDENT_SAA7111:
1540 saa711x_writeregs(client, saa7111_init);
1541 break;
1542 case V4L2_IDENT_SAA7113:
1543 saa711x_writeregs(client, saa7113_init);
1544 break;
1545 default:
Hans Verkuilb7f82922006-04-02 12:50:42 -03001546 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001547 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001548 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001549 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001550 saa711x_set_v4lstd(client, V4L2_STD_NTSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001551
1552 i2c_attach_client(client);
1553
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001554 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001555 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 -08001556
1557 return 0;
1558}
1559
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001560static int saa711x_probe(struct i2c_adapter *adapter)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001561{
Marco Schluessler4cbca182007-01-21 19:43:38 -03001562 if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001563 return i2c_probe(adapter, &addr_data, &saa711x_attach);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001564 return 0;
1565}
1566
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001567static int saa711x_detach(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001568{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001569 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001570 int err;
1571
1572 err = i2c_detach_client(client);
1573 if (err) {
1574 return err;
1575 }
1576
1577 kfree(state);
1578 kfree(client);
1579 return 0;
1580}
1581
1582/* ----------------------------------------------------------------------- */
1583
1584/* i2c implementation */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001585static struct i2c_driver i2c_driver_saa711x = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001586 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001587 .name = "saa7115",
1588 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001589 .id = I2C_DRIVERID_SAA711X,
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001590 .attach_adapter = saa711x_probe,
1591 .detach_client = saa711x_detach,
1592 .command = saa711x_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001593};
1594
1595
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001596static int __init saa711x_init_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001597{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001598 return i2c_add_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001599}
1600
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001601static void __exit saa711x_cleanup_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001602{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001603 i2c_del_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001604}
1605
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001606module_init(saa711x_init_module);
1607module_exit(saa711x_cleanup_module);