blob: c8e9cb3db30a9651692e3c4d732cca6a82643c06 [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
Hans Verkuile19b2fc2005-11-13 16:08:04 -080070I2C_CLIENT_INSMOD;
71
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030072struct saa711x_state {
Hans Verkuile19b2fc2005-11-13 16:08:04 -080073 v4l2_std_id std;
74 int input;
Marco Schluessler4cbca182007-01-21 19:43:38 -030075 int output;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080076 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020077 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080078 int bright;
79 int contrast;
80 int hue;
81 int sat;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030082 int width;
83 int height;
Hans Verkuil3434eb72007-04-27 12:31:08 -030084 u32 ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020085 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030086 u32 crystal_freq;
87 u8 ucgc;
88 u8 cgcdiv;
89 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080090};
91
92/* ----------------------------------------------------------------------- */
93
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030094static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080095{
96 return i2c_smbus_write_byte_data(client, reg, value);
97}
98
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030099/* Sanity routine to check if a register is present */
100static int saa711x_has_reg(const int id, const u8 reg)
101{
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300102 if (id == V4L2_IDENT_SAA7111)
103 return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
104 (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300105
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300106 /* common for saa7113/4/5/8 */
107 if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
108 reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
109 reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
110 reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300111 return 0;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300112
113 switch (id) {
114 case V4L2_IDENT_SAA7113:
115 return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
116 reg != 0x5d && reg < 0x63;
117 case V4L2_IDENT_SAA7114:
118 return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
119 (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
120 reg != 0x81 && reg < 0xf0;
121 case V4L2_IDENT_SAA7115:
122 return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
123 case V4L2_IDENT_SAA7118:
124 return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
125 (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
126 (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
127 }
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300128 return 1;
129}
130
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300131static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800132{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300133 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800134 unsigned char reg, data;
135
136 while (*regs != 0x00) {
137 reg = *(regs++);
138 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300139
140 /* According with datasheets, reserved regs should be
141 filled with 0 - seems better not to touch on they */
142 if (saa711x_has_reg(state->ident,reg)) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300143 if (saa711x_write(client, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300144 return -1;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300145 } else {
146 v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300147 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800148 }
149 return 0;
150}
151
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300152static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800153{
154 return i2c_smbus_read_byte_data(client, reg);
155}
156
157/* ----------------------------------------------------------------------- */
158
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300159/* SAA7111 initialization table */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300160static const unsigned char saa7111_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300161 R_01_INC_DELAY, 0x00, /* reserved */
162
163 /*front end */
164 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
165 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
166 * GAFIX=0, GAI1=256, GAI2=256 */
167 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
168 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
169
170 /* decoder */
171 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
172 * pixels after end of last line */
173 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
174 * work with NTSC, too */
175 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
176 * VTRC=1, HPLL=0, VNOI=0 */
177 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
178 * VBLB=0, UPTCV=0, APER=1 */
179 R_0A_LUMA_BRIGHT_CNTL, 0x80,
180 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
181 R_0C_CHROMA_SAT_CNTL, 0x40,
182 R_0D_CHROMA_HUE_CNTL, 0x00,
183 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
184 * FCTC=0, CHBW=1 */
185 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
186 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
187 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
188 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
189 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
190 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
191 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
192 R_15_VGATE_START_FID_CHG, 0x00,
193 R_16_VGATE_STOP, 0x00,
194 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
195
196 0x00, 0x00
197};
198
199/* SAA7113 init codes */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300200static const unsigned char saa7113_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300201 R_01_INC_DELAY, 0x08,
202 R_02_INPUT_CNTL_1, 0xc2,
203 R_03_INPUT_CNTL_2, 0x30,
204 R_04_INPUT_CNTL_3, 0x00,
205 R_05_INPUT_CNTL_4, 0x00,
206 R_06_H_SYNC_START, 0x89,
207 R_07_H_SYNC_STOP, 0x0d,
208 R_08_SYNC_CNTL, 0x88,
209 R_09_LUMA_CNTL, 0x01,
210 R_0A_LUMA_BRIGHT_CNTL, 0x80,
211 R_0B_LUMA_CONTRAST_CNTL, 0x47,
212 R_0C_CHROMA_SAT_CNTL, 0x40,
213 R_0D_CHROMA_HUE_CNTL, 0x00,
214 R_0E_CHROMA_CNTL_1, 0x01,
215 R_0F_CHROMA_GAIN_CNTL, 0x2a,
216 R_10_CHROMA_CNTL_2, 0x08,
217 R_11_MODE_DELAY_CNTL, 0x0c,
218 R_12_RT_SIGNAL_CNTL, 0x07,
219 R_13_RT_X_PORT_OUT_CNTL, 0x00,
220 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
221 R_15_VGATE_START_FID_CHG, 0x00,
222 R_16_VGATE_STOP, 0x00,
223 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
224
225 0x00, 0x00
226};
227
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800228/* If a value differs from the Hauppauge driver values, then the comment starts with
229 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
230 Hauppauge driver sets. */
231
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300232/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800233static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300234 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300235 R_01_INC_DELAY, 0x48, /* white peak control disabled */
236 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
237 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
238 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300239 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300240 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
241 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300242 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300243 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
244 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
245 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
246 R_0D_CHROMA_HUE_CNTL, 0x00,
247 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
248 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
249 R_11_MODE_DELAY_CNTL, 0x00,
250 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
251 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
252 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
253 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
254 R_19_RAW_DATA_OFF_CNTL, 0x80,
255 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
256 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
257 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
258 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300259
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300260
261 R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
262
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300263 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300264 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
265 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800266 0x00, 0x00
267};
268
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300269/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800270static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300271 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
272 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
273 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
274 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800275 0x00, 0x00
276};
277
278/* ============== SAA7715 VIDEO templates ============= */
279
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800280static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300281 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
282 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800283
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300284 R_15_VGATE_START_FID_CHG, 0x03,
285 R_16_VGATE_STOP, 0x11,
286 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800287
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300288 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
289 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800290
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300291 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800292
293 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300294 R_90_A_TASK_HANDLING_CNTL, 0x80,
295 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
296 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
297 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
298
299 /* hoffset low (input), 0x0002 is minimum */
300 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
301 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
302
303 /* hsize low (input), 0x02d0 = 720 */
304 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
305 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
306
307 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
308 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
309
310 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
311 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
312
313 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
314 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
315
316 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
317 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800318
319 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300320 R_C0_B_TASK_HANDLING_CNTL, 0x00,
321 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
322 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
323 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800324
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300325 /* 0x0002 is minimum */
326 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
327 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800328
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300329 /* 0x02d0 = 720 */
330 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
331 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
332
333 /* vwindow start 0x12 = 18 */
334 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
335 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
336
337 /* vwindow length 0xf8 = 248 */
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -0300338 R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
339 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300340
341 /* hwindow 0x02d0 = 720 */
342 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
343 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
344
345 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
346 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
347 R_F5_PULSGEN_LINE_LENGTH, 0xad,
348 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
349
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800350 0x00, 0x00
351};
352
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800353static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300354 R_80_GLOBAL_CNTL_1, 0x00,
355 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800356
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300357 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
358 R_16_VGATE_STOP, 0x16,
359 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800360
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300361 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
362 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800363
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300364 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800365
366 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300367 R_90_A_TASK_HANDLING_CNTL, 0x81,
368 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
369 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
370 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
371
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800372 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
373 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300374 /* hoffset low (input), 0x0002 is minimum */
375 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
376 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
377
378 /* hsize low (input), 0x02d0 = 720 */
379 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
380 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
381
382 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
383 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
384
385 /* vsize 0x12 = 18 */
386 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
387 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
388
389 /* hsize 0x05a0 = 1440 */
390 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
391 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
392 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
393 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800394
395 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300396 R_C0_B_TASK_HANDLING_CNTL, 0x00,
397 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
398 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
399 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800400
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300401 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
402 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
403 /* hoffset low (input), 0x0002 is minimum. See comment above. */
404 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
405 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800406
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300407 /* hsize 0x02d0 = 720 */
408 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
409 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
410
411 /* voffset 0x16 = 22 */
412 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
413 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
414
415 /* vsize 0x0120 = 288 */
416 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
417 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
418
419 /* hsize 0x02d0 = 720 */
420 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
421 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
422
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300423 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
424 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
425 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
426 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
427
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800428 0x00, 0x00
429};
430
431/* ============== SAA7715 VIDEO templates (end) ======= */
432
433static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300434 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
435 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
436 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
437 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
438 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
439
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800440 0x00, 0x00
441};
442
443static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300444 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
445 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
446 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
447 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
448 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
449
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800450 0x00, 0x00
451};
452
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300453
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800454static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300455 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300456 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
457 R_84_I_PORT_SIGNAL_DEF, 0x20,
458 R_85_I_PORT_SIGNAL_POLAR, 0x21,
459 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
460 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800461
462 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300463 R_A0_A_HORIZ_PRESCALING, 0x01,
464 R_A1_A_ACCUMULATION_LENGTH, 0x00,
465 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800466
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300467 /* Configure controls at nominal value*/
468 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
469 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
470 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
471
472 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
473 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
474 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
475
476 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
477
478 /* must be horiz lum scaling / 2 */
479 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
480 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
481
482 /* must be offset luma / 2 */
483 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
484
485 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
486 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
487
488 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
489 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
490
491 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
492
493 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
494 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
495 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
496 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
497
498 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
499 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
500 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
501 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800502
503 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300504 R_D0_B_HORIZ_PRESCALING, 0x01,
505 R_D1_B_ACCUMULATION_LENGTH, 0x00,
506 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800507
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300508 /* Configure controls at nominal value*/
509 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
510 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
511 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800512
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300513 /* hor lum scaling 0x0400 = 1 */
514 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
515 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
516
517 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
518
519 /* must be hor lum scaling / 2 */
520 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
521 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
522
523 /* must be offset luma / 2 */
524 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
525
526 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
527 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
528
529 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
530 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
531
532 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
533
534 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
535 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
536 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
537 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
538
539 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
540 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
541 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
542 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
543
544 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
545 R_F3_PLL_INCREMENT, 0x46,
546 R_F4_PLL2_STATUS, 0x00,
547 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
548 R_F8_PULSE_B_POS, 0x00,
549 R_F9_PULSE_B_POS_MSB, 0x4b,
550 R_FA_PULSE_C_POS, 0x00,
551 R_FB_PULSE_C_POS_MSB, 0x4b,
552
553 /* PLL2 lock detection settings: 71 lines 50% phase error */
554 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800555
556 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300557 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
558 R_41_LCR_BASE, 0xff,
559 R_41_LCR_BASE+1, 0xff,
560 R_41_LCR_BASE+2, 0xff,
561 R_41_LCR_BASE+3, 0xff,
562 R_41_LCR_BASE+4, 0xff,
563 R_41_LCR_BASE+5, 0xff,
564 R_41_LCR_BASE+6, 0xff,
565 R_41_LCR_BASE+7, 0xff,
566 R_41_LCR_BASE+8, 0xff,
567 R_41_LCR_BASE+9, 0xff,
568 R_41_LCR_BASE+10, 0xff,
569 R_41_LCR_BASE+11, 0xff,
570 R_41_LCR_BASE+12, 0xff,
571 R_41_LCR_BASE+13, 0xff,
572 R_41_LCR_BASE+14, 0xff,
573 R_41_LCR_BASE+15, 0xff,
574 R_41_LCR_BASE+16, 0xff,
575 R_41_LCR_BASE+17, 0xff,
576 R_41_LCR_BASE+18, 0xff,
577 R_41_LCR_BASE+19, 0xff,
578 R_41_LCR_BASE+20, 0xff,
579 R_41_LCR_BASE+21, 0xff,
580 R_41_LCR_BASE+22, 0xff,
581 R_58_PROGRAM_FRAMING_CODE, 0x40,
582 R_59_H_OFF_FOR_SLICER, 0x47,
583 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
584 R_5D_DID, 0xbd,
585 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800586
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300587 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800588
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300589 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
590 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
591 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800592 0x00, 0x00
593};
594
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300595static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800596{
597 c ^= (c >> 4);
598 c ^= (c >> 2);
599 c ^= (c >> 1);
600
601 return c & 1;
602}
603
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300604static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800605{
606 static const u8 biphase_tbl[] = {
607 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
608 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
609 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
610 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
611 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
612 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
613 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
614 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
615 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
616 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
617 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
618 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
619 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
620 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
621 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
622 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
623 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
624 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
625 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
626 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
627 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
628 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
629 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
630 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
631 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
632 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
633 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
634 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
635 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
636 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
637 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
638 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
639 };
640 int i;
641 u8 c, err = 0;
642
643 for (i = 0; i < 2 * 13; i += 2) {
644 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
645 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
646 dst[i / 2] = c;
647 }
648 return err & 0xf0;
649}
650
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300651static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800652{
653 static const int wss_bits[8] = {
654 0, 0, 0, 1, 0, 1, 1, 1
655 };
656 unsigned char parity;
657 int wss = 0;
658 int i;
659
660 for (i = 0; i < 16; i++) {
661 int b1 = wss_bits[p[i] & 7];
662 int b2 = wss_bits[(p[i] >> 3) & 7];
663
664 if (b1 == b2)
665 return -1;
666 wss |= b2 << i;
667 }
668 parity = wss & 15;
669 parity ^= parity >> 2;
670 parity ^= parity >> 1;
671
672 if (!(parity & 1))
673 return -1;
674
675 return wss;
676}
677
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300678static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800679{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300680 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200681 u32 acpf;
682 u32 acni;
683 u32 hz;
684 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300685 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800686
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300687 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
688 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
689 return 0;
690
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200691 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200692
693 /* sanity check */
694 if (freq < 32000 || freq > 48000)
695 return -EINVAL;
696
697 /* hz is the refresh rate times 100 */
698 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
699 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
700 acpf = (25600 * freq) / hz;
701 /* acni = (256 * freq * 2^23) / crystal_frequency =
702 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300703 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200704 f = freq;
705 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300706 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200707 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300708 if (state->ucgc) {
709 acpf = acpf * state->cgcdiv / 16;
710 acni = acni * state->cgcdiv / 16;
711 acc = 0x80;
712 if (state->cgcdiv == 3)
713 acc |= 0x40;
714 }
715 if (state->apll)
716 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200717
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300718 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
719 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
720 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300721
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300722 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
723 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300724 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300725 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300726 (acpf >> 16) & 0x03);
727
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300728 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
729 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
730 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800731 state->audclk_freq = freq;
732 return 0;
733}
734
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300735static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800736{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300737 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800738
739 switch (ctrl->id) {
740 case V4L2_CID_BRIGHTNESS:
741 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200742 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800743 return -ERANGE;
744 }
745
746 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300747 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800748 break;
749
750 case V4L2_CID_CONTRAST:
751 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200752 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800753 return -ERANGE;
754 }
755
756 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300757 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800758 break;
759
760 case V4L2_CID_SATURATION:
761 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200762 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800763 return -ERANGE;
764 }
765
766 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300767 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800768 break;
769
770 case V4L2_CID_HUE:
771 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200772 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800773 return -ERANGE;
774 }
775
776 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300777 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800778 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200779
780 default:
781 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800782 }
783
784 return 0;
785}
786
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300787static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800788{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300789 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800790
791 switch (ctrl->id) {
792 case V4L2_CID_BRIGHTNESS:
793 ctrl->value = state->bright;
794 break;
795 case V4L2_CID_CONTRAST:
796 ctrl->value = state->contrast;
797 break;
798 case V4L2_CID_SATURATION:
799 ctrl->value = state->sat;
800 break;
801 case V4L2_CID_HUE:
802 ctrl->value = state->hue;
803 break;
804 default:
805 return -EINVAL;
806 }
807
808 return 0;
809}
810
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300811static int saa711x_set_size(struct i2c_client *client, int width, int height)
812{
813 struct saa711x_state *state = i2c_get_clientdata(client);
814 int HPSC, HFSC;
815 int VSCY;
816 int res;
817 int is_50hz = state->std & V4L2_STD_625_50;
818 int Vsrc = is_50hz ? 576 : 480;
819
820 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
821
822 /* FIXME need better bounds checking here */
823 if ((width < 1) || (width > 1440))
824 return -EINVAL;
825 if ((height < 1) || (height > Vsrc))
826 return -EINVAL;
827
828 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
829 /* Decoder only supports 720 columns and 480 or 576 lines */
830 if (width != 720)
831 return -EINVAL;
832 if (height != Vsrc)
833 return -EINVAL;
834 }
835
836 state->width = width;
837 state->height = height;
838
839 if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
840 return 0;
841
842 /* probably have a valid size, let's set it */
843 /* Set output width/height */
844 /* width */
845
846 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
847 (u8) (width & 0xff));
848 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
849 (u8) ((width >> 8) & 0xff));
850
851 /* Vertical Scaling uses height/2 */
852 res=height/2;
853
854 /* On 60Hz, it is using a higher Vertical Output Size */
855 if (!is_50hz)
Hans Verkuild0d30c02006-11-25 09:45:50 -0300856 res += (VRES_60HZ - 480) >> 1;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300857
858 /* height */
859 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
860 (u8) (res & 0xff));
861 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
862 (u8) ((res >> 8) & 0xff));
863
864 /* Scaling settings */
865 /* Hprescaler is floor(inres/outres) */
866 HPSC = (int)(720 / width);
867 /* 0 is not allowed (div. by zero) */
868 HPSC = HPSC ? HPSC : 1;
869 HFSC = (int)((1024 * 720) / (HPSC * width));
870 /* FIXME hardcodes to "Task B"
871 * write H prescaler integer */
872 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
873 (u8) (HPSC & 0x3f));
874
875 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
876 /* write H fine-scaling (luminance) */
877 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
878 (u8) (HFSC & 0xff));
879 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
880 (u8) ((HFSC >> 8) & 0xff));
881 /* write H fine-scaling (chrominance)
882 * must be lum/2, so i'll just bitshift :) */
883 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
884 (u8) ((HFSC >> 1) & 0xff));
885 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
886 (u8) ((HFSC >> 9) & 0xff));
887
888 VSCY = (int)((1024 * Vsrc) / height);
889 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
890
891 /* Correct Contrast and Luminance */
892 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
893 (u8) (64 * 1024 / VSCY));
894 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
895 (u8) (64 * 1024 / VSCY));
896
897 /* write V fine-scaling (luminance) */
898 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
899 (u8) (VSCY & 0xff));
900 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
901 (u8) ((VSCY >> 8) & 0xff));
902 /* write V fine-scaling (chrominance) */
903 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
904 (u8) (VSCY & 0xff));
905 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
906 (u8) ((VSCY >> 8) & 0xff));
907
908 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
909
910 /* Activates task "B" */
911 saa711x_write(client, R_80_GLOBAL_CNTL_1,
Hans Verkuild0d30c02006-11-25 09:45:50 -0300912 saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300913
914 return 0;
915}
916
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300917static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800918{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300919 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800920
Hans Verkuil30b54d52006-01-09 15:25:43 -0200921 /* Prevent unnecessary standard changes. During a standard
922 change the I-Port is temporarily disabled. Any devices
923 reading from that port can get confused.
924 Note that VIDIOC_S_STD is also used to switch from
925 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
926 all I2C devices then you do not want to have an unwanted
927 side-effect here. */
928 if (std == state->std)
929 return;
930
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300931 state->std = std;
932
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800933 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
934 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200935 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300936 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300937 saa711x_set_size(client, 720, 480);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800938 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200939 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300940 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300941 saa711x_set_size(client, 720, 576);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800942 }
943
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300944 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300945 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300946 50 Hz / 625 lines 60 Hz / 525 lines
947 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
948 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
949 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
950 011 NTSC N (3.58MHz) PAL M (3.58MHz)
951 100 reserved NTSC-Japan (3.58MHz)
952 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300953 if (state->ident == V4L2_IDENT_SAA7111 ||
954 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300955 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300956
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300957 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300958 reg |= 0x30;
Hans Verkuile0028022008-04-22 14:45:51 -0300959 } else if (std == V4L2_STD_PAL_Nc) {
Hans Verkuil01342352006-03-25 08:19:47 -0300960 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300961 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300962 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300963 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300964 reg |= 0x40;
Mauro Carvalho Chehaba9aaec42007-03-13 13:41:49 -0300965 } else if (std & V4L2_STD_SECAM) {
Pádraig Bradyfc2fa312006-10-09 08:02:17 -0300966 reg |= 0x50;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300967 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300968 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300969 } else {
970 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300971 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300972
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300973 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300974 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300975 }
976
977 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300978 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300979 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800980}
981
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300982static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800983{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300984 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800985
986 return state->std;
987}
988
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300989static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800990{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300991 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800992 int reg1e, reg1f;
993 int signalOk;
994 int vcr;
995
Hans Verkuilfac9e892006-01-09 15:32:40 -0200996 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300997 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800998 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300999 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001000 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -02001001 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
1002 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001003 return;
1004 }
1005
1006 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001007 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
1008 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001009
1010 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1011 vcr = !(reg1f & 0x10);
1012
Hans Verkuil21fa7152006-01-09 15:25:41 -02001013 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001014 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001015 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001016 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001017 }
Hans Verkuilfac9e892006-01-09 15:32:40 -02001018 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1019 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001020
1021 switch (reg1e & 0x03) {
1022 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001023 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001024 break;
1025 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001026 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001027 break;
1028 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001029 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001030 break;
1031 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001032 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001033 break;
1034 }
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001035 v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001036}
1037
1038/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001039static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001040{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001041 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001042 int is_50hz = (state->std & V4L2_STD_625_50);
1043 u8 lcr[24];
1044 int i, x;
1045
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001046#if 1
1047 /* saa7113/7114/7118 VBI support are experimental */
1048 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
1049 return;
1050
1051#else
1052 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001053 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001054 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001055#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001056
1057 for (i = 0; i <= 23; i++)
1058 lcr[i] = 0xff;
1059
Hans Verkuila8b86432008-10-04 08:05:30 -03001060 if (fmt == NULL) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001061 /* raw VBI */
1062 if (is_50hz)
1063 for (i = 6; i <= 23; i++)
1064 lcr[i] = 0xdd;
1065 else
1066 for (i = 10; i <= 21; i++)
1067 lcr[i] = 0xdd;
1068 } else {
1069 /* sliced VBI */
1070 /* first clear lines that cannot be captured */
1071 if (is_50hz) {
1072 for (i = 0; i <= 5; i++)
1073 fmt->service_lines[0][i] =
1074 fmt->service_lines[1][i] = 0;
1075 }
1076 else {
1077 for (i = 0; i <= 9; i++)
1078 fmt->service_lines[0][i] =
1079 fmt->service_lines[1][i] = 0;
1080 for (i = 22; i <= 23; i++)
1081 fmt->service_lines[0][i] =
1082 fmt->service_lines[1][i] = 0;
1083 }
1084
1085 /* Now set the lcr values according to the specified service */
1086 for (i = 6; i <= 23; i++) {
1087 lcr[i] = 0;
1088 for (x = 0; x <= 1; x++) {
1089 switch (fmt->service_lines[1-x][i]) {
1090 case 0:
1091 lcr[i] |= 0xf << (4 * x);
1092 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001093 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001094 lcr[i] |= 1 << (4 * x);
1095 break;
1096 case V4L2_SLICED_CAPTION_525:
1097 lcr[i] |= 4 << (4 * x);
1098 break;
1099 case V4L2_SLICED_WSS_625:
1100 lcr[i] |= 5 << (4 * x);
1101 break;
1102 case V4L2_SLICED_VPS:
1103 lcr[i] |= 7 << (4 * x);
1104 break;
1105 }
1106 }
1107 }
1108 }
1109
1110 /* write the lcr registers */
1111 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001112 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001113 }
1114
1115 /* enable/disable raw VBI capturing */
Hans Verkuila8b86432008-10-04 08:05:30 -03001116 saa711x_writeregs(client, fmt == NULL ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001117 saa7115_cfg_vbi_on :
1118 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001119}
1120
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001121static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001122{
1123 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001124 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001125 0, V4L2_SLICED_CAPTION_525, /* 4 */
1126 V4L2_SLICED_WSS_625, 0, /* 5 */
1127 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1128 0, 0, 0, 0
1129 };
1130 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1131 int i;
1132
1133 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1134 return -EINVAL;
1135 memset(sliced, 0, sizeof(*sliced));
1136 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001137 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001138 return 0;
1139 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001140 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001141
1142 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1143 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1144 sliced->service_set |=
1145 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1146 }
1147 return 0;
1148}
1149
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001150static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1151{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001152 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001153 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001154 return 0;
1155 }
Hans Verkuila8b86432008-10-04 08:05:30 -03001156 if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
1157 saa711x_set_lcr(client, NULL);
1158 return 0;
1159 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001160 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1161 return -EINVAL;
1162
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001163 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001164}
1165
1166/* Decode the sliced VBI data stream as created by the saa7115.
1167 The format is described in the saa7115 datasheet in Tables 25 and 26
1168 and in Figure 33.
1169 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001170 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001171 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001172static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001173 struct v4l2_decode_vbi_line *vbi)
1174{
1175 static const char vbi_no_data_pattern[] = {
1176 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1177 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001178 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001179 u8 *p = vbi->p;
1180 u32 wss;
1181 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1182
1183 vbi->type = 0; /* mark result as a failure */
1184 id1 = p[2];
1185 id2 = p[3];
1186 /* Note: the field bit is inverted for 60 Hz video */
1187 if (state->std & V4L2_STD_525_60)
1188 id1 ^= 0x40;
1189
1190 /* Skip internal header, p now points to the start of the payload */
1191 p += 4;
1192 vbi->p = p;
1193
1194 /* calculate field and line number of the VBI packet (1-23) */
1195 vbi->is_second_field = ((id1 & 0x40) != 0);
1196 vbi->line = (id1 & 0x3f) << 3;
1197 vbi->line |= (id2 & 0x70) >> 4;
1198
1199 /* Obtain data type */
1200 id2 &= 0xf;
1201
1202 /* If the VBI slicer does not detect any signal it will fill up
1203 the payload buffer with 0xa0 bytes. */
1204 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1205 return;
1206
1207 /* decode payloads */
1208 switch (id2) {
1209 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001210 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001211 break;
1212 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001213 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001214 return;
1215 vbi->type = V4L2_SLICED_CAPTION_525;
1216 break;
1217 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001218 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001219 if (wss == -1)
1220 return;
1221 p[0] = wss & 0xff;
1222 p[1] = wss >> 8;
1223 vbi->type = V4L2_SLICED_WSS_625;
1224 break;
1225 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001226 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001227 return;
1228 vbi->type = V4L2_SLICED_VPS;
1229 break;
1230 default:
1231 return;
1232 }
1233}
1234
1235/* ============ SAA7115 AUDIO settings (end) ============= */
1236
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001237static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001238{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001239 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001240
1241 /* ioctls to allow direct access to the saa7115 registers for testing */
1242 switch (cmd) {
1243 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001244 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001245
1246 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001247 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001248
1249 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001250 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001251
1252 case VIDIOC_G_TUNER:
1253 {
1254 struct v4l2_tuner *vt = arg;
1255 int status;
1256
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001257 if (state->radio)
1258 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001259 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001260
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001261 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001262 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1263 break;
1264 }
1265
1266 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001267 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001268 break;
1269
1270 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001271 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001272
1273 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001274 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001275
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001276 case VIDIOC_QUERYCTRL:
1277 {
1278 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001279
Hans Verkuil18318e02006-06-18 14:49:52 -03001280 switch (qc->id) {
1281 case V4L2_CID_BRIGHTNESS:
1282 case V4L2_CID_CONTRAST:
1283 case V4L2_CID_SATURATION:
1284 case V4L2_CID_HUE:
1285 return v4l2_ctrl_query_fill_std(qc);
1286 default:
1287 return -EINVAL;
1288 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001289 }
1290
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001291 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001292 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001293 break;
1294
1295 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001296 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001297 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001298 break;
1299
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001300 case AUDC_SET_RADIO:
1301 state->radio = 1;
1302 break;
1303
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001304 case VIDIOC_INT_G_VIDEO_ROUTING:
1305 {
1306 struct v4l2_routing *route = arg;
1307
1308 route->input = state->input;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001309 route->output = state->output;
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001310 break;
1311 }
1312
1313 case VIDIOC_INT_S_VIDEO_ROUTING:
1314 {
1315 struct v4l2_routing *route = arg;
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001316 u32 input = route->input;
1317 u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001318
Marco Schluessler4cbca182007-01-21 19:43:38 -03001319 v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001320 /* saa7111/3 does not have these inputs */
1321 if ((state->ident == V4L2_IDENT_SAA7113 ||
1322 state->ident == V4L2_IDENT_SAA7111) &&
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001323 (route->input == SAA7115_COMPOSITE4 ||
1324 route->input == SAA7115_COMPOSITE5)) {
1325 return -EINVAL;
1326 }
1327 if (route->input > SAA7115_SVIDEO3)
1328 return -EINVAL;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001329 if (route->output > SAA7115_IPORT_ON)
1330 return -EINVAL;
1331 if (state->input == route->input && state->output == route->output)
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001332 break;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001333 v4l_dbg(1, debug, client, "now setting %s input %s output\n",
1334 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001335 state->input = route->input;
1336
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001337 /* saa7111 has slightly different input numbering */
1338 if (state->ident == V4L2_IDENT_SAA7111) {
1339 if (input >= SAA7115_COMPOSITE4)
1340 input -= 2;
1341 /* saa7111 specific */
1342 saa711x_write(client, R_10_CHROMA_CNTL_2,
1343 (saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
1344 ((route->output & 0xc0) ^ 0x40));
1345 saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
1346 (saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
1347 ((route->output & 2) ? 0x0a : 0));
1348 }
1349
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001350 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001351 saa711x_write(client, R_02_INPUT_CNTL_1,
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001352 (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
1353 input);
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001354
1355 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001356 saa711x_write(client, R_09_LUMA_CNTL,
1357 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001358 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
Marco Schluessler4cbca182007-01-21 19:43:38 -03001359
1360 state->output = route->output;
1361 if (state->ident == V4L2_IDENT_SAA7114 ||
1362 state->ident == V4L2_IDENT_SAA7115) {
1363 saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
1364 (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
1365 (state->output & 0x01));
1366 }
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001367 break;
1368 }
1369
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001370 case VIDIOC_STREAMON:
1371 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001372 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001373 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1374
1375 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1376 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001377 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001378 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1379 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001380 }
1381 break;
1382
Hans Verkuilb7f82922006-04-02 12:50:42 -03001383 case VIDIOC_INT_S_CRYSTAL_FREQ:
1384 {
1385 struct v4l2_crystal_freq *freq = arg;
1386
1387 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1388 freq->freq != SAA7115_FREQ_24_576_MHZ)
1389 return -EINVAL;
1390 state->crystal_freq = freq->freq;
1391 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1392 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1393 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001394 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001395 break;
1396 }
1397
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001398 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001399 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001400 break;
1401
1402 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001403 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001404 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001405 break;
1406
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001407 case VIDIOC_INT_S_GPIO:
1408 if (state->ident != V4L2_IDENT_SAA7111)
1409 return -EINVAL;
1410 saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
1411 (*(u32 *)arg ? 0x80 : 0));
1412 break;
1413
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001414 case VIDIOC_INT_G_VBI_DATA:
1415 {
1416 struct v4l2_sliced_vbi_data *data = arg;
1417
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001418 /* Note: the internal field ID is inverted for NTSC,
1419 so data->field 0 maps to the saa7115 even field,
1420 whereas for PAL it maps to the saa7115 odd field. */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001421 switch (data->id) {
1422 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001423 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001424 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001425 data->data[0] = saa711x_read(client, 0x6c);
1426 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001427 return 0;
1428 case V4L2_SLICED_CAPTION_525:
1429 if (data->field == 0) {
1430 /* CC */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001431 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001432 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001433 data->data[0] = saa711x_read(client, 0x69);
1434 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001435 return 0;
1436 }
1437 /* XDS */
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001438 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001439 return -EIO;
Hans Verkuilfaeb4ab2007-02-03 06:35:07 -03001440 data->data[0] = saa711x_read(client, 0x67);
1441 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001442 return 0;
1443 default:
1444 return -EINVAL;
1445 }
1446 break;
1447 }
1448
1449#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001450 case VIDIOC_DBG_G_REGISTER:
Trent Piepho52ebc762007-01-23 22:38:13 -03001451 case VIDIOC_DBG_S_REGISTER:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001452 {
1453 struct v4l2_register *reg = arg;
1454
Hans Verkuilf3d092b2007-02-23 20:55:14 -03001455 if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001456 return -EINVAL;
1457 if (!capable(CAP_SYS_ADMIN))
1458 return -EPERM;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001459 if (cmd == VIDIOC_DBG_G_REGISTER)
1460 reg->val = saa711x_read(client, reg->reg & 0xff);
1461 else
1462 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001463 break;
1464 }
1465#endif
1466
Hans Verkuil3434eb72007-04-27 12:31:08 -03001467 case VIDIOC_G_CHIP_IDENT:
1468 return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001469
1470 default:
1471 return -EINVAL;
1472 }
1473
1474 return 0;
1475}
1476
1477/* ----------------------------------------------------------------------- */
1478
Jean Delvared2653e92008-04-29 23:11:39 +02001479static int saa7115_probe(struct i2c_client *client,
1480 const struct i2c_device_id *id)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001481{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001482 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001483 int i;
1484 char name[17];
Jean Delvareaf294862008-05-18 20:49:40 +02001485 char chip_id;
1486 int autodetect = !id || id->driver_data == 1;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001487
1488 /* Check if the adapter supports the needed features */
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001489 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Hans Verkuil188f3452007-09-16 10:47:15 -03001490 return -EIO;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001491
Hans Verkuild0d30c02006-11-25 09:45:50 -03001492 for (i = 0; i < 0x0f; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001493 saa711x_write(client, 0, i);
Hans Verkuild0d30c02006-11-25 09:45:50 -03001494 name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
1495 if (name[i] > '9')
1496 name[i] += 'a' - '9' - 1;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001497 }
Hans Verkuild0d30c02006-11-25 09:45:50 -03001498 name[i] = '\0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001499
Jean Delvareaf294862008-05-18 20:49:40 +02001500 chip_id = name[5];
Mauro Carvalho Chehab3e7d3e52006-09-01 18:39:05 -03001501
Hans Verkuilf7668162006-11-25 09:40:28 -03001502 /* Check whether this chip is part of the saa711x series */
1503 if (memcmp(name, "1f711", 5)) {
1504 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 -03001505 client->addr << 1, name);
Hans Verkuil188f3452007-09-16 10:47:15 -03001506 return -ENODEV;
Hans Verkuilf7668162006-11-25 09:40:28 -03001507 }
1508
Jean Delvareaf294862008-05-18 20:49:40 +02001509 /* Safety check */
1510 if (!autodetect && id->name[6] != chip_id) {
1511 v4l_warn(client, "found saa711%c while %s was expected\n",
1512 chip_id, id->name);
1513 }
1514 snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
1515 v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
1516 client->addr << 1, client->adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001517
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001518 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuilc5bf2042008-09-03 17:12:09 -03001519 if (state == NULL)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001520 return -ENOMEM;
Hans Verkuilc5bf2042008-09-03 17:12:09 -03001521 i2c_set_clientdata(client, state);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001522 state->input = -1;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001523 state->output = SAA7115_IPORT_ON;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001524 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001525 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001526 state->bright = 128;
1527 state->contrast = 64;
1528 state->hue = 0;
1529 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001530 switch (chip_id) {
Jean Delvareaf294862008-05-18 20:49:40 +02001531 case '1':
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001532 state->ident = V4L2_IDENT_SAA7111;
1533 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001534 case '3':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001535 state->ident = V4L2_IDENT_SAA7113;
1536 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001537 case '4':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001538 state->ident = V4L2_IDENT_SAA7114;
1539 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001540 case '5':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001541 state->ident = V4L2_IDENT_SAA7115;
1542 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001543 case '8':
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001544 state->ident = V4L2_IDENT_SAA7118;
1545 break;
1546 default:
1547 state->ident = V4L2_IDENT_SAA7111;
1548 v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
1549
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001550 }
1551
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001552 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001553
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001554 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001555
1556 /* init to 60hz/48khz */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001557 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
1558 switch (state->ident) {
1559 case V4L2_IDENT_SAA7111:
1560 saa711x_writeregs(client, saa7111_init);
1561 break;
1562 case V4L2_IDENT_SAA7113:
1563 saa711x_writeregs(client, saa7113_init);
1564 break;
1565 default:
Hans Verkuilb7f82922006-04-02 12:50:42 -03001566 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001567 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001568 }
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001569 if (state->ident != V4L2_IDENT_SAA7111)
1570 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001571 saa711x_set_v4lstd(client, V4L2_STD_NTSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001572
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001573 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001574 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 -08001575 return 0;
1576}
1577
1578/* ----------------------------------------------------------------------- */
1579
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001580static int saa7115_remove(struct i2c_client *client)
1581{
1582 kfree(i2c_get_clientdata(client));
1583 return 0;
1584}
1585
Jean Delvareaf294862008-05-18 20:49:40 +02001586static const struct i2c_device_id saa7115_id[] = {
Hans Verkuil9edd350f2008-07-17 13:22:51 -03001587 { "saa7115_auto", 1 }, /* autodetect */
Jean Delvareaf294862008-05-18 20:49:40 +02001588 { "saa7111", 0 },
1589 { "saa7113", 0 },
1590 { "saa7114", 0 },
1591 { "saa7115", 0 },
1592 { "saa7118", 0 },
1593 { }
1594};
1595MODULE_DEVICE_TABLE(i2c, saa7115_id);
1596
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001597static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1598 .name = "saa7115",
1599 .driverid = I2C_DRIVERID_SAA711X,
1600 .command = saa7115_command,
1601 .probe = saa7115_probe,
1602 .remove = saa7115_remove,
1603 .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
Jean Delvareaf294862008-05-18 20:49:40 +02001604 .id_table = saa7115_id,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001605};