blob: 416d05d4a969088d02d2f1c5a319de4fb215fe68 [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 Verkuil3434eb72007-04-27 12:31:08 -030048#include <media/v4l2-chip-ident.h>
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -030049#include <media/v4l2-i2c-drv-legacy.h>
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -030050#include <media/saa7115.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020051#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080052
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -030053#define VRES_60HZ (480+16)
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030054
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030055MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030056MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
57 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080058MODULE_LICENSE("GPL");
59
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030060static int debug;
Hans Verkuilfac9e892006-01-09 15:32:40 -020061module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080062
63MODULE_PARM_DESC(debug, "Debug level (0-1)");
64
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030065static unsigned short normal_i2c[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030066 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
67 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030068 I2C_CLIENT_END };
Hans Verkuile19b2fc2005-11-13 16:08:04 -080069
70
71I2C_CLIENT_INSMOD;
72
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -030073struct saa711x_state {
Hans Verkuile19b2fc2005-11-13 16:08:04 -080074 v4l2_std_id std;
75 int input;
Marco Schluessler4cbca182007-01-21 19:43:38 -030076 int output;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080077 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020078 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080079 int bright;
80 int contrast;
81 int hue;
82 int sat;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030083 int width;
84 int height;
Hans Verkuil3434eb72007-04-27 12:31:08 -030085 u32 ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020086 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030087 u32 crystal_freq;
88 u8 ucgc;
89 u8 cgcdiv;
90 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080091};
92
93/* ----------------------------------------------------------------------- */
94
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -030095static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080096{
97 return i2c_smbus_write_byte_data(client, reg, value);
98}
99
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300100/* Sanity routine to check if a register is present */
101static int saa711x_has_reg(const int id, const u8 reg)
102{
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300103 if (id == V4L2_IDENT_SAA7111)
104 return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
105 (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300106
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300107 /* common for saa7113/4/5/8 */
108 if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
109 reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
110 reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
111 reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300112 return 0;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300113
114 switch (id) {
115 case V4L2_IDENT_SAA7113:
116 return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
117 reg != 0x5d && reg < 0x63;
118 case V4L2_IDENT_SAA7114:
119 return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
120 (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
121 reg != 0x81 && reg < 0xf0;
122 case V4L2_IDENT_SAA7115:
123 return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
124 case V4L2_IDENT_SAA7118:
125 return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
126 (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
127 (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
128 }
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300129 return 1;
130}
131
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300132static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800133{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300134 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800135 unsigned char reg, data;
136
137 while (*regs != 0x00) {
138 reg = *(regs++);
139 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300140
141 /* According with datasheets, reserved regs should be
142 filled with 0 - seems better not to touch on they */
143 if (saa711x_has_reg(state->ident,reg)) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300144 if (saa711x_write(client, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300145 return -1;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300146 } else {
147 v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300148 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800149 }
150 return 0;
151}
152
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300153static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800154{
155 return i2c_smbus_read_byte_data(client, reg);
156}
157
158/* ----------------------------------------------------------------------- */
159
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300160/* SAA7111 initialization table */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300161static const unsigned char saa7111_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300162 R_01_INC_DELAY, 0x00, /* reserved */
163
164 /*front end */
165 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
166 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
167 * GAFIX=0, GAI1=256, GAI2=256 */
168 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
169 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
170
171 /* decoder */
172 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
173 * pixels after end of last line */
174 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
175 * work with NTSC, too */
176 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
177 * VTRC=1, HPLL=0, VNOI=0 */
178 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
179 * VBLB=0, UPTCV=0, APER=1 */
180 R_0A_LUMA_BRIGHT_CNTL, 0x80,
181 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
182 R_0C_CHROMA_SAT_CNTL, 0x40,
183 R_0D_CHROMA_HUE_CNTL, 0x00,
184 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
185 * FCTC=0, CHBW=1 */
186 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
187 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
188 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
189 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
190 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
191 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
192 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
193 R_15_VGATE_START_FID_CHG, 0x00,
194 R_16_VGATE_STOP, 0x00,
195 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
196
197 0x00, 0x00
198};
199
200/* SAA7113 init codes */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300201static const unsigned char saa7113_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300202 R_01_INC_DELAY, 0x08,
203 R_02_INPUT_CNTL_1, 0xc2,
204 R_03_INPUT_CNTL_2, 0x30,
205 R_04_INPUT_CNTL_3, 0x00,
206 R_05_INPUT_CNTL_4, 0x00,
207 R_06_H_SYNC_START, 0x89,
208 R_07_H_SYNC_STOP, 0x0d,
209 R_08_SYNC_CNTL, 0x88,
210 R_09_LUMA_CNTL, 0x01,
211 R_0A_LUMA_BRIGHT_CNTL, 0x80,
212 R_0B_LUMA_CONTRAST_CNTL, 0x47,
213 R_0C_CHROMA_SAT_CNTL, 0x40,
214 R_0D_CHROMA_HUE_CNTL, 0x00,
215 R_0E_CHROMA_CNTL_1, 0x01,
216 R_0F_CHROMA_GAIN_CNTL, 0x2a,
217 R_10_CHROMA_CNTL_2, 0x08,
218 R_11_MODE_DELAY_CNTL, 0x0c,
219 R_12_RT_SIGNAL_CNTL, 0x07,
220 R_13_RT_X_PORT_OUT_CNTL, 0x00,
221 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
222 R_15_VGATE_START_FID_CHG, 0x00,
223 R_16_VGATE_STOP, 0x00,
224 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
225
226 0x00, 0x00
227};
228
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800229/* If a value differs from the Hauppauge driver values, then the comment starts with
230 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
231 Hauppauge driver sets. */
232
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300233/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800234static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300235 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300236 R_01_INC_DELAY, 0x48, /* white peak control disabled */
237 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
238 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
239 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300240 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300241 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
242 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300243 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300244 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
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300261
262 R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
263
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300264 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300265 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
266 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800267 0x00, 0x00
268};
269
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300270/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800271static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300272 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
273 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
274 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
275 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800276 0x00, 0x00
277};
278
279/* ============== SAA7715 VIDEO templates ============= */
280
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800281static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300282 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
283 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800284
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300285 R_15_VGATE_START_FID_CHG, 0x03,
286 R_16_VGATE_STOP, 0x11,
287 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800288
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300289 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
290 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800291
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300292 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800293
294 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300295 R_90_A_TASK_HANDLING_CNTL, 0x80,
296 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
297 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
298 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
299
300 /* hoffset low (input), 0x0002 is minimum */
301 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
302 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
303
304 /* hsize low (input), 0x02d0 = 720 */
305 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
306 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
307
308 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
309 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
310
311 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
312 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
313
314 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
315 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
316
317 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
318 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800319
320 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300321 R_C0_B_TASK_HANDLING_CNTL, 0x00,
322 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
323 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
324 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800325
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300326 /* 0x0002 is minimum */
327 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
328 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800329
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300330 /* 0x02d0 = 720 */
331 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
332 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
333
334 /* vwindow start 0x12 = 18 */
335 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
336 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
337
338 /* vwindow length 0xf8 = 248 */
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -0300339 R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
340 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300341
342 /* hwindow 0x02d0 = 720 */
343 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
344 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
345
346 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
347 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
348 R_F5_PULSGEN_LINE_LENGTH, 0xad,
349 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
350
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800351 0x00, 0x00
352};
353
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800354static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300355 R_80_GLOBAL_CNTL_1, 0x00,
356 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800357
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300358 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
359 R_16_VGATE_STOP, 0x16,
360 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800361
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300362 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
363 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800364
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300365 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800366
367 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300368 R_90_A_TASK_HANDLING_CNTL, 0x81,
369 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
370 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
371 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
372
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800373 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
374 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300375 /* hoffset low (input), 0x0002 is minimum */
376 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
377 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
378
379 /* hsize low (input), 0x02d0 = 720 */
380 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
381 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
382
383 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
384 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
385
386 /* vsize 0x12 = 18 */
387 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
388 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
389
390 /* hsize 0x05a0 = 1440 */
391 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
392 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
393 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
394 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800395
396 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300397 R_C0_B_TASK_HANDLING_CNTL, 0x00,
398 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
399 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
400 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800401
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300402 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
403 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
404 /* hoffset low (input), 0x0002 is minimum. See comment above. */
405 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
406 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800407
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300408 /* hsize 0x02d0 = 720 */
409 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
410 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
411
412 /* voffset 0x16 = 22 */
413 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
414 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
415
416 /* vsize 0x0120 = 288 */
417 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
418 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
419
420 /* hsize 0x02d0 = 720 */
421 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
422 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
423
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300424 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
425 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
426 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
427 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
428
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800429 0x00, 0x00
430};
431
432/* ============== SAA7715 VIDEO templates (end) ======= */
433
434static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300435 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
436 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
437 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
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
444static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300445 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
446 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
447 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
448 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
449 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
450
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800451 0x00, 0x00
452};
453
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300454
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800455static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300456 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300457 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
458 R_84_I_PORT_SIGNAL_DEF, 0x20,
459 R_85_I_PORT_SIGNAL_POLAR, 0x21,
460 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
461 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800462
463 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300464 R_A0_A_HORIZ_PRESCALING, 0x01,
465 R_A1_A_ACCUMULATION_LENGTH, 0x00,
466 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800467
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300468 /* Configure controls at nominal value*/
469 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
470 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
471 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
472
473 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
474 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
475 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
476
477 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
478
479 /* must be horiz lum scaling / 2 */
480 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
481 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
482
483 /* must be offset luma / 2 */
484 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
485
486 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
487 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
488
489 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
490 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
491
492 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
493
494 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
495 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
496 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
497 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
498
499 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
500 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
501 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
502 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800503
504 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300505 R_D0_B_HORIZ_PRESCALING, 0x01,
506 R_D1_B_ACCUMULATION_LENGTH, 0x00,
507 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800508
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300509 /* Configure controls at nominal value*/
510 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
511 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
512 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800513
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300514 /* hor lum scaling 0x0400 = 1 */
515 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
516 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
517
518 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
519
520 /* must be hor lum scaling / 2 */
521 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
522 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
523
524 /* must be offset luma / 2 */
525 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
526
527 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
528 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
529
530 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
531 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
532
533 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
534
535 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
536 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
537 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
538 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
539
540 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
541 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
542 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
543 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
544
545 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
546 R_F3_PLL_INCREMENT, 0x46,
547 R_F4_PLL2_STATUS, 0x00,
548 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
549 R_F8_PULSE_B_POS, 0x00,
550 R_F9_PULSE_B_POS_MSB, 0x4b,
551 R_FA_PULSE_C_POS, 0x00,
552 R_FB_PULSE_C_POS_MSB, 0x4b,
553
554 /* PLL2 lock detection settings: 71 lines 50% phase error */
555 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800556
557 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300558 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
559 R_41_LCR_BASE, 0xff,
560 R_41_LCR_BASE+1, 0xff,
561 R_41_LCR_BASE+2, 0xff,
562 R_41_LCR_BASE+3, 0xff,
563 R_41_LCR_BASE+4, 0xff,
564 R_41_LCR_BASE+5, 0xff,
565 R_41_LCR_BASE+6, 0xff,
566 R_41_LCR_BASE+7, 0xff,
567 R_41_LCR_BASE+8, 0xff,
568 R_41_LCR_BASE+9, 0xff,
569 R_41_LCR_BASE+10, 0xff,
570 R_41_LCR_BASE+11, 0xff,
571 R_41_LCR_BASE+12, 0xff,
572 R_41_LCR_BASE+13, 0xff,
573 R_41_LCR_BASE+14, 0xff,
574 R_41_LCR_BASE+15, 0xff,
575 R_41_LCR_BASE+16, 0xff,
576 R_41_LCR_BASE+17, 0xff,
577 R_41_LCR_BASE+18, 0xff,
578 R_41_LCR_BASE+19, 0xff,
579 R_41_LCR_BASE+20, 0xff,
580 R_41_LCR_BASE+21, 0xff,
581 R_41_LCR_BASE+22, 0xff,
582 R_58_PROGRAM_FRAMING_CODE, 0x40,
583 R_59_H_OFF_FOR_SLICER, 0x47,
584 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
585 R_5D_DID, 0xbd,
586 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800587
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300588 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800589
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300590 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
591 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
592 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800593 0x00, 0x00
594};
595
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300596static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800597{
598 c ^= (c >> 4);
599 c ^= (c >> 2);
600 c ^= (c >> 1);
601
602 return c & 1;
603}
604
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300605static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800606{
607 static const u8 biphase_tbl[] = {
608 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
609 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
610 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
611 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
612 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
613 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
614 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
615 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
616 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
617 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
618 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
619 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
620 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
621 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
622 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
623 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
624 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
625 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
626 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
627 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
628 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
629 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
630 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
631 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
632 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
633 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
634 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
635 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
636 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
637 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
638 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
639 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
640 };
641 int i;
642 u8 c, err = 0;
643
644 for (i = 0; i < 2 * 13; i += 2) {
645 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
646 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
647 dst[i / 2] = c;
648 }
649 return err & 0xf0;
650}
651
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300652static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800653{
654 static const int wss_bits[8] = {
655 0, 0, 0, 1, 0, 1, 1, 1
656 };
657 unsigned char parity;
658 int wss = 0;
659 int i;
660
661 for (i = 0; i < 16; i++) {
662 int b1 = wss_bits[p[i] & 7];
663 int b2 = wss_bits[(p[i] >> 3) & 7];
664
665 if (b1 == b2)
666 return -1;
667 wss |= b2 << i;
668 }
669 parity = wss & 15;
670 parity ^= parity >> 2;
671 parity ^= parity >> 1;
672
673 if (!(parity & 1))
674 return -1;
675
676 return wss;
677}
678
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300679static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800680{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300681 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200682 u32 acpf;
683 u32 acni;
684 u32 hz;
685 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300686 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800687
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300688 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
689 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
690 return 0;
691
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200692 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200693
694 /* sanity check */
695 if (freq < 32000 || freq > 48000)
696 return -EINVAL;
697
698 /* hz is the refresh rate times 100 */
699 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
700 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
701 acpf = (25600 * freq) / hz;
702 /* acni = (256 * freq * 2^23) / crystal_frequency =
703 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300704 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200705 f = freq;
706 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300707 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200708 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300709 if (state->ucgc) {
710 acpf = acpf * state->cgcdiv / 16;
711 acni = acni * state->cgcdiv / 16;
712 acc = 0x80;
713 if (state->cgcdiv == 3)
714 acc |= 0x40;
715 }
716 if (state->apll)
717 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200718
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300719 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
720 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
721 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300722
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300723 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
724 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300725 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300726 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300727 (acpf >> 16) & 0x03);
728
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300729 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
730 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
731 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800732 state->audclk_freq = freq;
733 return 0;
734}
735
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300736static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800737{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300738 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800739
740 switch (ctrl->id) {
741 case V4L2_CID_BRIGHTNESS:
742 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200743 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800744 return -ERANGE;
745 }
746
747 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300748 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800749 break;
750
751 case V4L2_CID_CONTRAST:
752 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200753 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800754 return -ERANGE;
755 }
756
757 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300758 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800759 break;
760
761 case V4L2_CID_SATURATION:
762 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200763 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800764 return -ERANGE;
765 }
766
767 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300768 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800769 break;
770
771 case V4L2_CID_HUE:
772 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200773 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800774 return -ERANGE;
775 }
776
777 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300778 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800779 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200780
781 default:
782 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800783 }
784
785 return 0;
786}
787
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300788static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800789{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300790 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800791
792 switch (ctrl->id) {
793 case V4L2_CID_BRIGHTNESS:
794 ctrl->value = state->bright;
795 break;
796 case V4L2_CID_CONTRAST:
797 ctrl->value = state->contrast;
798 break;
799 case V4L2_CID_SATURATION:
800 ctrl->value = state->sat;
801 break;
802 case V4L2_CID_HUE:
803 ctrl->value = state->hue;
804 break;
805 default:
806 return -EINVAL;
807 }
808
809 return 0;
810}
811
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300812static int saa711x_set_size(struct i2c_client *client, int width, int height)
813{
814 struct saa711x_state *state = i2c_get_clientdata(client);
815 int HPSC, HFSC;
816 int VSCY;
817 int res;
818 int is_50hz = state->std & V4L2_STD_625_50;
819 int Vsrc = is_50hz ? 576 : 480;
820
821 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
822
823 /* FIXME need better bounds checking here */
824 if ((width < 1) || (width > 1440))
825 return -EINVAL;
826 if ((height < 1) || (height > Vsrc))
827 return -EINVAL;
828
829 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
830 /* Decoder only supports 720 columns and 480 or 576 lines */
831 if (width != 720)
832 return -EINVAL;
833 if (height != Vsrc)
834 return -EINVAL;
835 }
836
837 state->width = width;
838 state->height = height;
839
840 if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
841 return 0;
842
843 /* probably have a valid size, let's set it */
844 /* Set output width/height */
845 /* width */
846
847 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
848 (u8) (width & 0xff));
849 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
850 (u8) ((width >> 8) & 0xff));
851
852 /* Vertical Scaling uses height/2 */
853 res=height/2;
854
855 /* On 60Hz, it is using a higher Vertical Output Size */
856 if (!is_50hz)
Hans Verkuild0d30c02006-11-25 09:45:50 -0300857 res += (VRES_60HZ - 480) >> 1;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300858
859 /* height */
860 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
861 (u8) (res & 0xff));
862 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
863 (u8) ((res >> 8) & 0xff));
864
865 /* Scaling settings */
866 /* Hprescaler is floor(inres/outres) */
867 HPSC = (int)(720 / width);
868 /* 0 is not allowed (div. by zero) */
869 HPSC = HPSC ? HPSC : 1;
870 HFSC = (int)((1024 * 720) / (HPSC * width));
871 /* FIXME hardcodes to "Task B"
872 * write H prescaler integer */
873 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
874 (u8) (HPSC & 0x3f));
875
876 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
877 /* write H fine-scaling (luminance) */
878 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
879 (u8) (HFSC & 0xff));
880 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
881 (u8) ((HFSC >> 8) & 0xff));
882 /* write H fine-scaling (chrominance)
883 * must be lum/2, so i'll just bitshift :) */
884 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
885 (u8) ((HFSC >> 1) & 0xff));
886 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
887 (u8) ((HFSC >> 9) & 0xff));
888
889 VSCY = (int)((1024 * Vsrc) / height);
890 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
891
892 /* Correct Contrast and Luminance */
893 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
894 (u8) (64 * 1024 / VSCY));
895 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
896 (u8) (64 * 1024 / VSCY));
897
898 /* write V fine-scaling (luminance) */
899 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
900 (u8) (VSCY & 0xff));
901 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
902 (u8) ((VSCY >> 8) & 0xff));
903 /* write V fine-scaling (chrominance) */
904 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
905 (u8) (VSCY & 0xff));
906 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
907 (u8) ((VSCY >> 8) & 0xff));
908
909 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
910
911 /* Activates task "B" */
912 saa711x_write(client, R_80_GLOBAL_CNTL_1,
Hans Verkuild0d30c02006-11-25 09:45:50 -0300913 saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300914
915 return 0;
916}
917
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300918static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800919{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300920 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800921
Hans Verkuil30b54d52006-01-09 15:25:43 -0200922 /* Prevent unnecessary standard changes. During a standard
923 change the I-Port is temporarily disabled. Any devices
924 reading from that port can get confused.
925 Note that VIDIOC_S_STD is also used to switch from
926 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
927 all I2C devices then you do not want to have an unwanted
928 side-effect here. */
929 if (std == state->std)
930 return;
931
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300932 state->std = std;
933
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800934 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
935 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200936 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300937 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300938 saa711x_set_size(client, 720, 480);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800939 } else {
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -0200940 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300941 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300942 saa711x_set_size(client, 720, 576);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800943 }
944
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300945 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300946 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300947 50 Hz / 625 lines 60 Hz / 525 lines
948 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
949 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
950 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
951 011 NTSC N (3.58MHz) PAL M (3.58MHz)
952 100 reserved NTSC-Japan (3.58MHz)
953 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300954 if (state->ident == V4L2_IDENT_SAA7111 ||
955 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300956 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300957
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300958 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300959 reg |= 0x30;
Hans Verkuile0028022008-04-22 14:45:51 -0300960 } else if (std == V4L2_STD_PAL_Nc) {
Hans Verkuil01342352006-03-25 08:19:47 -0300961 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300962 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300963 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300964 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300965 reg |= 0x40;
Mauro Carvalho Chehaba9aaec42007-03-13 13:41:49 -0300966 } else if (std & V4L2_STD_SECAM) {
Pádraig Bradyfc2fa312006-10-09 08:02:17 -0300967 reg |= 0x50;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300968 }
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300969 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300970 } else {
971 /* restart task B if needed */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300972 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300973
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300974 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300975 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300976 }
977
978 /* switch audio mode too! */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300979 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300980 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800981}
982
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300983static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800984{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300985 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800986
987 return state->std;
988}
989
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300990static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800991{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -0300992 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800993 int reg1e, reg1f;
994 int signalOk;
995 int vcr;
996
Hans Verkuilfac9e892006-01-09 15:32:40 -0200997 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300998 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800999 /* status for the saa7114 */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001000 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001001 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -02001002 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
1003 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001004 return;
1005 }
1006
1007 /* status for the saa7115 */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001008 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
1009 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001010
1011 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1012 vcr = !(reg1f & 0x10);
1013
Hans Verkuil21fa7152006-01-09 15:25:41 -02001014 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001015 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001016 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001017 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001018 }
Hans Verkuilfac9e892006-01-09 15:32:40 -02001019 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1020 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001021
1022 switch (reg1e & 0x03) {
1023 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001024 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001025 break;
1026 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001027 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001028 break;
1029 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001030 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001031 break;
1032 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001033 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001034 break;
1035 }
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001036 v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001037}
1038
1039/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001040static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001041{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001042 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001043 int is_50hz = (state->std & V4L2_STD_625_50);
1044 u8 lcr[24];
1045 int i, x;
1046
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001047#if 1
1048 /* saa7113/7114/7118 VBI support are experimental */
1049 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
1050 return;
1051
1052#else
1053 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001054 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001055 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001056#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001057
1058 for (i = 0; i <= 23; i++)
1059 lcr[i] = 0xff;
1060
1061 if (fmt->service_set == 0) {
1062 /* raw VBI */
1063 if (is_50hz)
1064 for (i = 6; i <= 23; i++)
1065 lcr[i] = 0xdd;
1066 else
1067 for (i = 10; i <= 21; i++)
1068 lcr[i] = 0xdd;
1069 } else {
1070 /* sliced VBI */
1071 /* first clear lines that cannot be captured */
1072 if (is_50hz) {
1073 for (i = 0; i <= 5; i++)
1074 fmt->service_lines[0][i] =
1075 fmt->service_lines[1][i] = 0;
1076 }
1077 else {
1078 for (i = 0; i <= 9; i++)
1079 fmt->service_lines[0][i] =
1080 fmt->service_lines[1][i] = 0;
1081 for (i = 22; i <= 23; i++)
1082 fmt->service_lines[0][i] =
1083 fmt->service_lines[1][i] = 0;
1084 }
1085
1086 /* Now set the lcr values according to the specified service */
1087 for (i = 6; i <= 23; i++) {
1088 lcr[i] = 0;
1089 for (x = 0; x <= 1; x++) {
1090 switch (fmt->service_lines[1-x][i]) {
1091 case 0:
1092 lcr[i] |= 0xf << (4 * x);
1093 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001094 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001095 lcr[i] |= 1 << (4 * x);
1096 break;
1097 case V4L2_SLICED_CAPTION_525:
1098 lcr[i] |= 4 << (4 * x);
1099 break;
1100 case V4L2_SLICED_WSS_625:
1101 lcr[i] |= 5 << (4 * x);
1102 break;
1103 case V4L2_SLICED_VPS:
1104 lcr[i] |= 7 << (4 * x);
1105 break;
1106 }
1107 }
1108 }
1109 }
1110
1111 /* write the lcr registers */
1112 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001113 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001114 }
1115
1116 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001117 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001118 saa7115_cfg_vbi_on :
1119 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001120}
1121
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001122static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001123{
1124 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001125 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001126 0, V4L2_SLICED_CAPTION_525, /* 4 */
1127 V4L2_SLICED_WSS_625, 0, /* 5 */
1128 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1129 0, 0, 0, 0
1130 };
1131 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1132 int i;
1133
1134 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1135 return -EINVAL;
1136 memset(sliced, 0, sizeof(*sliced));
1137 /* done if using raw VBI */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001138 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001139 return 0;
1140 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001141 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001142
1143 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1144 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1145 sliced->service_set |=
1146 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1147 }
1148 return 0;
1149}
1150
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001151static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1152{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001153 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001154 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001155 return 0;
1156 }
1157 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1158 return -EINVAL;
1159
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001160 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001161}
1162
1163/* Decode the sliced VBI data stream as created by the saa7115.
1164 The format is described in the saa7115 datasheet in Tables 25 and 26
1165 and in Figure 33.
1166 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001167 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168 code. */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001169static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001170 struct v4l2_decode_vbi_line *vbi)
1171{
1172 static const char vbi_no_data_pattern[] = {
1173 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1174 };
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001175 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001176 u8 *p = vbi->p;
1177 u32 wss;
1178 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1179
1180 vbi->type = 0; /* mark result as a failure */
1181 id1 = p[2];
1182 id2 = p[3];
1183 /* Note: the field bit is inverted for 60 Hz video */
1184 if (state->std & V4L2_STD_525_60)
1185 id1 ^= 0x40;
1186
1187 /* Skip internal header, p now points to the start of the payload */
1188 p += 4;
1189 vbi->p = p;
1190
1191 /* calculate field and line number of the VBI packet (1-23) */
1192 vbi->is_second_field = ((id1 & 0x40) != 0);
1193 vbi->line = (id1 & 0x3f) << 3;
1194 vbi->line |= (id2 & 0x70) >> 4;
1195
1196 /* Obtain data type */
1197 id2 &= 0xf;
1198
1199 /* If the VBI slicer does not detect any signal it will fill up
1200 the payload buffer with 0xa0 bytes. */
1201 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1202 return;
1203
1204 /* decode payloads */
1205 switch (id2) {
1206 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001207 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001208 break;
1209 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001210 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001211 return;
1212 vbi->type = V4L2_SLICED_CAPTION_525;
1213 break;
1214 case 5:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001215 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001216 if (wss == -1)
1217 return;
1218 p[0] = wss & 0xff;
1219 p[1] = wss >> 8;
1220 vbi->type = V4L2_SLICED_WSS_625;
1221 break;
1222 case 7:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001223 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001224 return;
1225 vbi->type = V4L2_SLICED_VPS;
1226 break;
1227 default:
1228 return;
1229 }
1230}
1231
1232/* ============ SAA7115 AUDIO settings (end) ============= */
1233
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001234static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001235{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001236 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001237
1238 /* ioctls to allow direct access to the saa7115 registers for testing */
1239 switch (cmd) {
1240 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001241 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001242
1243 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001244 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001245
1246 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001247 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001248
1249 case VIDIOC_G_TUNER:
1250 {
1251 struct v4l2_tuner *vt = arg;
1252 int status;
1253
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001254 if (state->radio)
1255 break;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001256 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001257
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001258 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001259 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1260 break;
1261 }
1262
1263 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001264 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001265 break;
1266
1267 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001268 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001269
1270 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001271 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001272
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001273 case VIDIOC_QUERYCTRL:
1274 {
1275 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001276
Hans Verkuil18318e02006-06-18 14:49:52 -03001277 switch (qc->id) {
1278 case V4L2_CID_BRIGHTNESS:
1279 case V4L2_CID_CONTRAST:
1280 case V4L2_CID_SATURATION:
1281 case V4L2_CID_HUE:
1282 return v4l2_ctrl_query_fill_std(qc);
1283 default:
1284 return -EINVAL;
1285 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001286 }
1287
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001288 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001289 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001290 break;
1291
1292 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001293 state->radio = 0;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001294 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001295 break;
1296
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001297 case AUDC_SET_RADIO:
1298 state->radio = 1;
1299 break;
1300
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001301 case VIDIOC_INT_G_VIDEO_ROUTING:
1302 {
1303 struct v4l2_routing *route = arg;
1304
1305 route->input = state->input;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001306 route->output = state->output;
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001307 break;
1308 }
1309
1310 case VIDIOC_INT_S_VIDEO_ROUTING:
1311 {
1312 struct v4l2_routing *route = arg;
1313
Marco Schluessler4cbca182007-01-21 19:43:38 -03001314 v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001315 /* saa7113 does not have these inputs */
1316 if (state->ident == V4L2_IDENT_SAA7113 &&
1317 (route->input == SAA7115_COMPOSITE4 ||
1318 route->input == SAA7115_COMPOSITE5)) {
1319 return -EINVAL;
1320 }
1321 if (route->input > SAA7115_SVIDEO3)
1322 return -EINVAL;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001323 if (route->output > SAA7115_IPORT_ON)
1324 return -EINVAL;
1325 if (state->input == route->input && state->output == route->output)
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001326 break;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001327 v4l_dbg(1, debug, client, "now setting %s input %s output\n",
1328 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001329 state->input = route->input;
1330
1331 /* select mode */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001332 saa711x_write(client, R_02_INPUT_CNTL_1,
1333 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001334 state->input);
1335
1336 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001337 saa711x_write(client, R_09_LUMA_CNTL,
1338 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001339 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
Marco Schluessler4cbca182007-01-21 19:43:38 -03001340
1341 state->output = route->output;
1342 if (state->ident == V4L2_IDENT_SAA7114 ||
1343 state->ident == V4L2_IDENT_SAA7115) {
1344 saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
1345 (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
1346 (state->output & 0x01));
1347 }
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001348 break;
1349 }
1350
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001351 case VIDIOC_STREAMON:
1352 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001353 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001354 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1355
1356 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1357 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001358 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001359 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1360 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001361 }
1362 break;
1363
Hans Verkuilb7f82922006-04-02 12:50:42 -03001364 case VIDIOC_INT_S_CRYSTAL_FREQ:
1365 {
1366 struct v4l2_crystal_freq *freq = arg;
1367
1368 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1369 freq->freq != SAA7115_FREQ_24_576_MHZ)
1370 return -EINVAL;
1371 state->crystal_freq = freq->freq;
1372 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1373 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1374 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001375 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001376 break;
1377 }
1378
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001379 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001380 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001381 break;
1382
1383 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001384 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001385 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001386 break;
1387
1388 case VIDIOC_INT_G_VBI_DATA:
1389 {
1390 struct v4l2_sliced_vbi_data *data = arg;
1391
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001392 /* Note: the internal field ID is inverted for NTSC,
1393 so data->field 0 maps to the saa7115 even field,
1394 whereas for PAL it maps to the saa7115 odd field. */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001395 switch (data->id) {
1396 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001397 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001398 return -EIO;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001399 data->data[0] = saa711x_read(client, 0x6c);
1400 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001401 return 0;
1402 case V4L2_SLICED_CAPTION_525:
1403 if (data->field == 0) {
1404 /* CC */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001405 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001406 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001407 data->data[0] = saa711x_read(client, 0x69);
1408 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001409 return 0;
1410 }
1411 /* XDS */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001412 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001413 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001414 data->data[0] = saa711x_read(client, 0x67);
1415 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001416 return 0;
1417 default:
1418 return -EINVAL;
1419 }
1420 break;
1421 }
1422
1423#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001424 case VIDIOC_DBG_G_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -03001425 case VIDIOC_DBG_S_REGISTER:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001426 {
1427 struct v4l2_register *reg = arg;
1428
Hans Verkuilf3d092b2007-02-23 20:55:14 -03001429 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001430 return -EINVAL;
1431 if (!capable(CAP_SYS_ADMIN))
1432 return -EPERM;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001433 if (cmd == VIDIOC_DBG_G_REGISTER)
1434 reg->val = saa711x_read(client, reg->reg & 0xff);
1435 else
1436 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001437 break;
1438 }
1439#endif
1440
Hans Verkuil3434eb72007-04-27 12:31:08 -03001441 case VIDIOC_G_CHIP_IDENT:
1442 return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001443
1444 default:
1445 return -EINVAL;
1446 }
1447
1448 return 0;
1449}
1450
1451/* ----------------------------------------------------------------------- */
1452
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001453static int saa7115_probe(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001454{
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001455 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001456 int i;
1457 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001458 u8 chip_id;
1459
1460 /* Check if the adapter supports the needed features */
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001461 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Hans Verkuil188f3452007-09-16 10:47:15 -03001462 return -EIO;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001463
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001464 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1465
Hans Verkuild0d30c02006-11-25 09:45:50 -03001466 for (i = 0; i < 0x0f; i++) {
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001467 saa711x_write(client, 0, i);
Hans Verkuild0d30c02006-11-25 09:45:50 -03001468 name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
1469 if (name[i] > '9')
1470 name[i] += 'a' - '9' - 1;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001471 }
Hans Verkuild0d30c02006-11-25 09:45:50 -03001472 name[i] = '\0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001473
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001474 saa711x_write(client, 0, 5);
1475 chip_id = saa711x_read(client, 0) & 0x0f;
Mauro Carvalho Chehab3e7d3e52006-09-01 18:39:05 -03001476
Hans Verkuilf7668162006-11-25 09:40:28 -03001477 /* Check whether this chip is part of the saa711x series */
1478 if (memcmp(name, "1f711", 5)) {
1479 v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001480 client->addr << 1, name);
Hans Verkuil188f3452007-09-16 10:47:15 -03001481 return -ENODEV;
Hans Verkuilf7668162006-11-25 09:40:28 -03001482 }
1483
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001484 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001485 v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001486
Mauro Carvalho Chehab66ec1192006-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) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001490 return -ENOMEM;
1491 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001492 state->input = -1;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001493 state->output = SAA7115_IPORT_ON;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001494 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 Chehabf167cb42006-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 Chehab183d8962006-09-12 20:02:09 -03001527 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
1528 switch (state->ident) {
1529 case V4L2_IDENT_SAA7111:
1530 saa711x_writeregs(client, saa7111_init);
1531 break;
1532 case V4L2_IDENT_SAA7113:
1533 saa711x_writeregs(client, saa7113_init);
1534 break;
1535 default:
Hans Verkuilb7f82922006-04-02 12:50:42 -03001536 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001537 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001538 }
Mauro Carvalho Chehab66ec1192006-08-29 22:52:32 -03001539 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001540 saa711x_set_v4lstd(client, V4L2_STD_NTSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001541
Mauro Carvalho Chehabf167cb42006-01-11 19:41:49 -02001542 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001543 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 -08001544 return 0;
1545}
1546
1547/* ----------------------------------------------------------------------- */
1548
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001549static int saa7115_remove(struct i2c_client *client)
1550{
1551 kfree(i2c_get_clientdata(client));
1552 return 0;
1553}
1554
1555static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1556 .name = "saa7115",
1557 .driverid = I2C_DRIVERID_SAA711X,
1558 .command = saa7115_command,
1559 .probe = saa7115_probe,
1560 .remove = saa7115_remove,
1561 .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001562};
1563