blob: c2374ed7ba9fe31c35b37197bfd6b4a234911446 [file] [log] [blame]
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001/* saa711x - Philips SAA711x video decoder driver
2 * This driver can work with saa7111, saa7111a, saa7113, saa7114,
3 * saa7115 and saa7118.
Hans Verkuile19b2fc2005-11-13 16:08:04 -08004 *
5 * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
6 * the saa7111 driver by Dave Perks.
7 *
8 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
9 * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
10 *
11 * Slight changes for video timing and attachment output by
12 * Wolfgang Scherr <scherr@net4you.net>
13 *
14 * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
15 * by Ronald Bultje <rbultje@ronald.bitfreak.net>
16 *
17 * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
18 * (2/17/2003)
19 *
20 * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030021 *
22 * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
23 * SAA7111, SAA7113 and SAA7118 support
Hans Verkuile19b2fc2005-11-13 16:08:04 -080024 *
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * as published by the Free Software Foundation; either version 2
28 * of the License, or (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 */
39
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -030040#include "saa711x_regs.h"
Hans Verkuile19b2fc2005-11-13 16:08:04 -080041
42#include <linux/kernel.h>
43#include <linux/module.h>
44#include <linux/slab.h>
45#include <linux/i2c.h>
46#include <linux/videodev2.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080047#include <media/v4l2-common.h>
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -030048#include <media/saa7115.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020049#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080050
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -030051#define VRES_60HZ (480+16)
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030052
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030053MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030054MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
55 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080056MODULE_LICENSE("GPL");
57
58static int debug = 0;
Hans Verkuilfac9e892006-01-09 15:32:40 -020059module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080060
61MODULE_PARM_DESC(debug, "Debug level (0-1)");
62
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030063static unsigned short normal_i2c[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030064 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
65 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030066 I2C_CLIENT_END };
Hans Verkuile19b2fc2005-11-13 16:08:04 -080067
68
69I2C_CLIENT_INSMOD;
70
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030071struct saa711x_state {
Hans Verkuile19b2fc2005-11-13 16:08:04 -080072 v4l2_std_id std;
73 int input;
74 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020075 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080076 int bright;
77 int contrast;
78 int hue;
79 int sat;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030080 int width;
81 int height;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080082 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020083 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030084 u32 crystal_freq;
85 u8 ucgc;
86 u8 cgcdiv;
87 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080088};
89
90/* ----------------------------------------------------------------------- */
91
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030092static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080093{
94 return i2c_smbus_write_byte_data(client, reg, value);
95}
96
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030097/* Sanity routine to check if a register is present */
98static int saa711x_has_reg(const int id, const u8 reg)
99{
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300100 if (id == V4L2_IDENT_SAA7111)
101 return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
102 (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300103
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300104 /* common for saa7113/4/5/8 */
105 if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
106 reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
107 reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
108 reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300109 return 0;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300110
111 switch (id) {
112 case V4L2_IDENT_SAA7113:
113 return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
114 reg != 0x5d && reg < 0x63;
115 case V4L2_IDENT_SAA7114:
116 return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
117 (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
118 reg != 0x81 && reg < 0xf0;
119 case V4L2_IDENT_SAA7115:
120 return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
121 case V4L2_IDENT_SAA7118:
122 return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
123 (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
124 (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
125 }
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300126 return 1;
127}
128
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300129static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800130{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300131 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800132 unsigned char reg, data;
133
134 while (*regs != 0x00) {
135 reg = *(regs++);
136 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300137
138 /* According with datasheets, reserved regs should be
139 filled with 0 - seems better not to touch on they */
140 if (saa711x_has_reg(state->ident,reg)) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300141 if (saa711x_write(client, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300142 return -1;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300143 } else {
144 v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300145 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800146 }
147 return 0;
148}
149
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300150static inline int saa711x_read(struct i2c_client *client, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800151{
152 return i2c_smbus_read_byte_data(client, reg);
153}
154
155/* ----------------------------------------------------------------------- */
156
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300157/* SAA7111 initialization table */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300158static const unsigned char saa7111_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300159 R_01_INC_DELAY, 0x00, /* reserved */
160
161 /*front end */
162 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
163 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
164 * GAFIX=0, GAI1=256, GAI2=256 */
165 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
166 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
167
168 /* decoder */
169 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
170 * pixels after end of last line */
171 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
172 * work with NTSC, too */
173 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
174 * VTRC=1, HPLL=0, VNOI=0 */
175 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
176 * VBLB=0, UPTCV=0, APER=1 */
177 R_0A_LUMA_BRIGHT_CNTL, 0x80,
178 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
179 R_0C_CHROMA_SAT_CNTL, 0x40,
180 R_0D_CHROMA_HUE_CNTL, 0x00,
181 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
182 * FCTC=0, CHBW=1 */
183 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
184 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
185 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
186 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
187 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
188 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
189 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
190 R_15_VGATE_START_FID_CHG, 0x00,
191 R_16_VGATE_STOP, 0x00,
192 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
193
194 0x00, 0x00
195};
196
197/* SAA7113 init codes */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300198static const unsigned char saa7113_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300199 R_01_INC_DELAY, 0x08,
200 R_02_INPUT_CNTL_1, 0xc2,
201 R_03_INPUT_CNTL_2, 0x30,
202 R_04_INPUT_CNTL_3, 0x00,
203 R_05_INPUT_CNTL_4, 0x00,
204 R_06_H_SYNC_START, 0x89,
205 R_07_H_SYNC_STOP, 0x0d,
206 R_08_SYNC_CNTL, 0x88,
207 R_09_LUMA_CNTL, 0x01,
208 R_0A_LUMA_BRIGHT_CNTL, 0x80,
209 R_0B_LUMA_CONTRAST_CNTL, 0x47,
210 R_0C_CHROMA_SAT_CNTL, 0x40,
211 R_0D_CHROMA_HUE_CNTL, 0x00,
212 R_0E_CHROMA_CNTL_1, 0x01,
213 R_0F_CHROMA_GAIN_CNTL, 0x2a,
214 R_10_CHROMA_CNTL_2, 0x08,
215 R_11_MODE_DELAY_CNTL, 0x0c,
216 R_12_RT_SIGNAL_CNTL, 0x07,
217 R_13_RT_X_PORT_OUT_CNTL, 0x00,
218 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
219 R_15_VGATE_START_FID_CHG, 0x00,
220 R_16_VGATE_STOP, 0x00,
221 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
222
223 0x00, 0x00
224};
225
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800226/* If a value differs from the Hauppauge driver values, then the comment starts with
227 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
228 Hauppauge driver sets. */
229
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300230/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800231static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300232 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300233 R_01_INC_DELAY, 0x48, /* white peak control disabled */
234 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
235 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
236 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300237 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300238 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
239 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300240 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300241 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
242 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
243 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
244 R_0D_CHROMA_HUE_CNTL, 0x00,
245 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
246 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
247 R_11_MODE_DELAY_CNTL, 0x00,
248 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
249 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
250 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
251 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
252 R_19_RAW_DATA_OFF_CNTL, 0x80,
253 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
254 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
255 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
256 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300257
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300258
259 R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
260
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300261 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300262 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
263 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800264 0x00, 0x00
265};
266
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300267/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800268static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300269 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
270 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
271 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
272 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800273 0x00, 0x00
274};
275
276/* ============== SAA7715 VIDEO templates ============= */
277
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800278static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300279 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
280 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800281
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300282 R_15_VGATE_START_FID_CHG, 0x03,
283 R_16_VGATE_STOP, 0x11,
284 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800285
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300286 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
287 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800288
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300289 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800290
291 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300292 R_90_A_TASK_HANDLING_CNTL, 0x80,
293 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
294 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
295 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
296
297 /* hoffset low (input), 0x0002 is minimum */
298 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
299 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
300
301 /* hsize low (input), 0x02d0 = 720 */
302 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
303 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
304
305 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
306 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
307
308 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
309 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
310
311 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
312 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
313
314 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
315 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800316
317 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300318 R_C0_B_TASK_HANDLING_CNTL, 0x00,
319 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
320 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
321 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800322
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300323 /* 0x0002 is minimum */
324 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
325 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800326
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300327 /* 0x02d0 = 720 */
328 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
329 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
330
331 /* vwindow start 0x12 = 18 */
332 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
333 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
334
335 /* vwindow length 0xf8 = 248 */
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -0300336 R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
337 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300338
339 /* hwindow 0x02d0 = 720 */
340 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
341 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
342
343 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
344 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
345 R_F5_PULSGEN_LINE_LENGTH, 0xad,
346 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
347
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800348 0x00, 0x00
349};
350
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800351static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300352 R_80_GLOBAL_CNTL_1, 0x00,
353 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800354
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300355 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
356 R_16_VGATE_STOP, 0x16,
357 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800358
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300359 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
360 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800361
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300362 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800363
364 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300365 R_90_A_TASK_HANDLING_CNTL, 0x81,
366 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
367 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
368 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
369
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800370 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
371 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300372 /* hoffset low (input), 0x0002 is minimum */
373 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
374 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
375
376 /* hsize low (input), 0x02d0 = 720 */
377 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
378 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
379
380 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
381 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
382
383 /* vsize 0x12 = 18 */
384 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
385 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
386
387 /* hsize 0x05a0 = 1440 */
388 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
389 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
390 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
391 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800392
393 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300394 R_C0_B_TASK_HANDLING_CNTL, 0x00,
395 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
396 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
397 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800398
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300399 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
400 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
401 /* hoffset low (input), 0x0002 is minimum. See comment above. */
402 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
403 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800404
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300405 /* hsize 0x02d0 = 720 */
406 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
407 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
408
409 /* voffset 0x16 = 22 */
410 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
411 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
412
413 /* vsize 0x0120 = 288 */
414 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
415 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
416
417 /* hsize 0x02d0 = 720 */
418 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
419 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
420
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300421 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
422 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
423 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
424 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
425
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800426 0x00, 0x00
427};
428
429/* ============== SAA7715 VIDEO templates (end) ======= */
430
431static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300432 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
433 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
434 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
435 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
436 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
437
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800438 0x00, 0x00
439};
440
441static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300442 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
443 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
444 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
445 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
446 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
447
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800448 0x00, 0x00
449};
450
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300451
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800452static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300453 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300454 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
455 R_84_I_PORT_SIGNAL_DEF, 0x20,
456 R_85_I_PORT_SIGNAL_POLAR, 0x21,
457 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
458 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800459
460 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300461 R_A0_A_HORIZ_PRESCALING, 0x01,
462 R_A1_A_ACCUMULATION_LENGTH, 0x00,
463 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800464
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300465 /* Configure controls at nominal value*/
466 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
467 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
468 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
469
470 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
471 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
472 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
473
474 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
475
476 /* must be horiz lum scaling / 2 */
477 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
478 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
479
480 /* must be offset luma / 2 */
481 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
482
483 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
484 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
485
486 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
487 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
488
489 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
490
491 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
492 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
493 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
494 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
495
496 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
497 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
498 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
499 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800500
501 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300502 R_D0_B_HORIZ_PRESCALING, 0x01,
503 R_D1_B_ACCUMULATION_LENGTH, 0x00,
504 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800505
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300506 /* Configure controls at nominal value*/
507 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
508 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
509 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800510
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300511 /* hor lum scaling 0x0400 = 1 */
512 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
513 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
514
515 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
516
517 /* must be hor lum scaling / 2 */
518 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
519 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
520
521 /* must be offset luma / 2 */
522 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
523
524 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
525 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
526
527 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
528 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
529
530 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
531
532 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
533 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
534 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
535 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
536
537 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
538 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
539 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
540 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
541
542 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
543 R_F3_PLL_INCREMENT, 0x46,
544 R_F4_PLL2_STATUS, 0x00,
545 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
546 R_F8_PULSE_B_POS, 0x00,
547 R_F9_PULSE_B_POS_MSB, 0x4b,
548 R_FA_PULSE_C_POS, 0x00,
549 R_FB_PULSE_C_POS_MSB, 0x4b,
550
551 /* PLL2 lock detection settings: 71 lines 50% phase error */
552 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800553
554 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300555 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
556 R_41_LCR_BASE, 0xff,
557 R_41_LCR_BASE+1, 0xff,
558 R_41_LCR_BASE+2, 0xff,
559 R_41_LCR_BASE+3, 0xff,
560 R_41_LCR_BASE+4, 0xff,
561 R_41_LCR_BASE+5, 0xff,
562 R_41_LCR_BASE+6, 0xff,
563 R_41_LCR_BASE+7, 0xff,
564 R_41_LCR_BASE+8, 0xff,
565 R_41_LCR_BASE+9, 0xff,
566 R_41_LCR_BASE+10, 0xff,
567 R_41_LCR_BASE+11, 0xff,
568 R_41_LCR_BASE+12, 0xff,
569 R_41_LCR_BASE+13, 0xff,
570 R_41_LCR_BASE+14, 0xff,
571 R_41_LCR_BASE+15, 0xff,
572 R_41_LCR_BASE+16, 0xff,
573 R_41_LCR_BASE+17, 0xff,
574 R_41_LCR_BASE+18, 0xff,
575 R_41_LCR_BASE+19, 0xff,
576 R_41_LCR_BASE+20, 0xff,
577 R_41_LCR_BASE+21, 0xff,
578 R_41_LCR_BASE+22, 0xff,
579 R_58_PROGRAM_FRAMING_CODE, 0x40,
580 R_59_H_OFF_FOR_SLICER, 0x47,
581 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
582 R_5D_DID, 0xbd,
583 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800584
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300585 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800586
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300587 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
588 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
589 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800590 0x00, 0x00
591};
592
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300593static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800594{
595 c ^= (c >> 4);
596 c ^= (c >> 2);
597 c ^= (c >> 1);
598
599 return c & 1;
600}
601
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300602static int saa711x_decode_vps(u8 * dst, u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800603{
604 static const u8 biphase_tbl[] = {
605 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
606 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
607 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
608 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
609 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
610 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
611 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
612 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
613 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
614 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
615 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
616 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
617 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
618 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
619 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
620 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
621 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
622 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
623 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
624 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
625 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
626 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
627 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
628 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
629 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
630 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
631 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
632 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
633 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
634 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
635 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
636 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
637 };
638 int i;
639 u8 c, err = 0;
640
641 for (i = 0; i < 2 * 13; i += 2) {
642 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
643 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
644 dst[i / 2] = c;
645 }
646 return err & 0xf0;
647}
648
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300649static int saa711x_decode_wss(u8 * p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800650{
651 static const int wss_bits[8] = {
652 0, 0, 0, 1, 0, 1, 1, 1
653 };
654 unsigned char parity;
655 int wss = 0;
656 int i;
657
658 for (i = 0; i < 16; i++) {
659 int b1 = wss_bits[p[i] & 7];
660 int b2 = wss_bits[(p[i] >> 3) & 7];
661
662 if (b1 == b2)
663 return -1;
664 wss |= b2 << i;
665 }
666 parity = wss & 15;
667 parity ^= parity >> 2;
668 parity ^= parity >> 1;
669
670 if (!(parity & 1))
671 return -1;
672
673 return wss;
674}
675
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300676static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800677{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300678 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200679 u32 acpf;
680 u32 acni;
681 u32 hz;
682 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300683 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800684
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300685 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
686 if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
687 return 0;
688
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200689 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200690
691 /* sanity check */
692 if (freq < 32000 || freq > 48000)
693 return -EINVAL;
694
695 /* hz is the refresh rate times 100 */
696 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
697 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
698 acpf = (25600 * freq) / hz;
699 /* acni = (256 * freq * 2^23) / crystal_frequency =
700 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300701 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200702 f = freq;
703 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300704 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200705 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300706 if (state->ucgc) {
707 acpf = acpf * state->cgcdiv / 16;
708 acni = acni * state->cgcdiv / 16;
709 acc = 0x80;
710 if (state->cgcdiv == 3)
711 acc |= 0x40;
712 }
713 if (state->apll)
714 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200715
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300716 saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
717 saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
718 saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300719
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300720 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
721 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300722 (acpf >> 8) & 0xff);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300723 saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300724 (acpf >> 16) & 0x03);
725
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300726 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
727 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
728 saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800729 state->audclk_freq = freq;
730 return 0;
731}
732
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300733static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800734{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300735 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800736
737 switch (ctrl->id) {
738 case V4L2_CID_BRIGHTNESS:
739 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200740 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800741 return -ERANGE;
742 }
743
744 state->bright = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300745 saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800746 break;
747
748 case V4L2_CID_CONTRAST:
749 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200750 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800751 return -ERANGE;
752 }
753
754 state->contrast = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300755 saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800756 break;
757
758 case V4L2_CID_SATURATION:
759 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200760 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800761 return -ERANGE;
762 }
763
764 state->sat = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300765 saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800766 break;
767
768 case V4L2_CID_HUE:
769 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200770 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800771 return -ERANGE;
772 }
773
774 state->hue = ctrl->value;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300775 saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800776 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200777
778 default:
779 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800780 }
781
782 return 0;
783}
784
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300785static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800786{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300787 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800788
789 switch (ctrl->id) {
790 case V4L2_CID_BRIGHTNESS:
791 ctrl->value = state->bright;
792 break;
793 case V4L2_CID_CONTRAST:
794 ctrl->value = state->contrast;
795 break;
796 case V4L2_CID_SATURATION:
797 ctrl->value = state->sat;
798 break;
799 case V4L2_CID_HUE:
800 ctrl->value = state->hue;
801 break;
802 default:
803 return -EINVAL;
804 }
805
806 return 0;
807}
808
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300809static int saa711x_set_size(struct i2c_client *client, int width, int height)
810{
811 struct saa711x_state *state = i2c_get_clientdata(client);
812 int HPSC, HFSC;
813 int VSCY;
814 int res;
815 int is_50hz = state->std & V4L2_STD_625_50;
816 int Vsrc = is_50hz ? 576 : 480;
817
818 v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
819
820 /* FIXME need better bounds checking here */
821 if ((width < 1) || (width > 1440))
822 return -EINVAL;
823 if ((height < 1) || (height > Vsrc))
824 return -EINVAL;
825
826 if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
827 /* Decoder only supports 720 columns and 480 or 576 lines */
828 if (width != 720)
829 return -EINVAL;
830 if (height != Vsrc)
831 return -EINVAL;
832 }
833
834 state->width = width;
835 state->height = height;
836
837 if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
838 return 0;
839
840 /* probably have a valid size, let's set it */
841 /* Set output width/height */
842 /* width */
843
844 saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
845 (u8) (width & 0xff));
846 saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
847 (u8) ((width >> 8) & 0xff));
848
849 /* Vertical Scaling uses height/2 */
850 res=height/2;
851
852 /* On 60Hz, it is using a higher Vertical Output Size */
853 if (!is_50hz)
Hans Verkuild0d30c02006-11-25 09:45:50 -0300854 res += (VRES_60HZ - 480) >> 1;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300855
856 /* height */
857 saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
858 (u8) (res & 0xff));
859 saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
860 (u8) ((res >> 8) & 0xff));
861
862 /* Scaling settings */
863 /* Hprescaler is floor(inres/outres) */
864 HPSC = (int)(720 / width);
865 /* 0 is not allowed (div. by zero) */
866 HPSC = HPSC ? HPSC : 1;
867 HFSC = (int)((1024 * 720) / (HPSC * width));
868 /* FIXME hardcodes to "Task B"
869 * write H prescaler integer */
870 saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
871 (u8) (HPSC & 0x3f));
872
873 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
874 /* write H fine-scaling (luminance) */
875 saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
876 (u8) (HFSC & 0xff));
877 saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
878 (u8) ((HFSC >> 8) & 0xff));
879 /* write H fine-scaling (chrominance)
880 * must be lum/2, so i'll just bitshift :) */
881 saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
882 (u8) ((HFSC >> 1) & 0xff));
883 saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
884 (u8) ((HFSC >> 9) & 0xff));
885
886 VSCY = (int)((1024 * Vsrc) / height);
887 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
888
889 /* Correct Contrast and Luminance */
890 saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
891 (u8) (64 * 1024 / VSCY));
892 saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
893 (u8) (64 * 1024 / VSCY));
894
895 /* write V fine-scaling (luminance) */
896 saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
897 (u8) (VSCY & 0xff));
898 saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
899 (u8) ((VSCY >> 8) & 0xff));
900 /* write V fine-scaling (chrominance) */
901 saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
902 (u8) (VSCY & 0xff));
903 saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
904 (u8) ((VSCY >> 8) & 0xff));
905
906 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
907
908 /* Activates task "B" */
909 saa711x_write(client, R_80_GLOBAL_CNTL_1,
Hans Verkuild0d30c02006-11-25 09:45:50 -0300910 saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300911
912 return 0;
913}
914
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300915static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800916{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300917 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800918
Hans Verkuil30b54d52006-01-09 15:25:43 -0200919 /* Prevent unnecessary standard changes. During a standard
920 change the I-Port is temporarily disabled. Any devices
921 reading from that port can get confused.
922 Note that VIDIOC_S_STD is also used to switch from
923 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
924 all I2C devices then you do not want to have an unwanted
925 side-effect here. */
926 if (std == state->std)
927 return;
928
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300929 state->std = std;
930
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800931 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
932 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200933 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300934 saa711x_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300935 saa711x_set_size(client, 720, 480);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800936 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200937 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300938 saa711x_writeregs(client, saa7115_cfg_50hz_video);
Hans Verkuild0d30c02006-11-25 09:45:50 -0300939 saa711x_set_size(client, 720, 576);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800940 }
941
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300942 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300943 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300944 50 Hz / 625 lines 60 Hz / 525 lines
945 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
946 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
947 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
948 011 NTSC N (3.58MHz) PAL M (3.58MHz)
949 100 reserved NTSC-Japan (3.58MHz)
950 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300951 if (state->ident == V4L2_IDENT_SAA7111 ||
952 state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300953 u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300954
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300955 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300956 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300957 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300958 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300959 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300960 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300961 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300962 reg |= 0x40;
Pádraig Bradyfc2fa312006-10-09 08:02:17 -0300963 } else if (std == V4L2_STD_SECAM) {
964 reg |= 0x50;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300965 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300966 saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300967 } else {
968 /* restart task B if needed */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300969 int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300970
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300971 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300972 saa711x_writeregs(client, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300973 }
974
975 /* switch audio mode too! */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300976 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300977 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800978}
979
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300980static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800981{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300982 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800983
984 return state->std;
985}
986
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300987static void saa711x_log_status(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800988{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300989 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800990 int reg1e, reg1f;
991 int signalOk;
992 int vcr;
993
Hans Verkuilfac9e892006-01-09 15:32:40 -0200994 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300995 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800996 /* status for the saa7114 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300997 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800998 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200999 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
1000 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001001 return;
1002 }
1003
1004 /* status for the saa7115 */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001005 reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
1006 reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001007
1008 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1009 vcr = !(reg1f & 0x10);
1010
Hans Verkuil21fa7152006-01-09 15:25:41 -02001011 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001012 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001013 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -02001014 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -02001015 }
Hans Verkuilfac9e892006-01-09 15:32:40 -02001016 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1017 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001018
1019 switch (reg1e & 0x03) {
1020 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001021 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001022 break;
1023 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001024 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001025 break;
1026 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001027 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001028 break;
1029 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -02001030 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001031 break;
1032 }
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001033 v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001034}
1035
1036/* setup the sliced VBI lcr registers according to the sliced VBI format */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001037static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001038{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001039 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001040 int is_50hz = (state->std & V4L2_STD_625_50);
1041 u8 lcr[24];
1042 int i, x;
1043
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001044#if 1
1045 /* saa7113/7114/7118 VBI support are experimental */
1046 if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
1047 return;
1048
1049#else
1050 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001051 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001052 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001053#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001054
1055 for (i = 0; i <= 23; i++)
1056 lcr[i] = 0xff;
1057
1058 if (fmt->service_set == 0) {
1059 /* raw VBI */
1060 if (is_50hz)
1061 for (i = 6; i <= 23; i++)
1062 lcr[i] = 0xdd;
1063 else
1064 for (i = 10; i <= 21; i++)
1065 lcr[i] = 0xdd;
1066 } else {
1067 /* sliced VBI */
1068 /* first clear lines that cannot be captured */
1069 if (is_50hz) {
1070 for (i = 0; i <= 5; i++)
1071 fmt->service_lines[0][i] =
1072 fmt->service_lines[1][i] = 0;
1073 }
1074 else {
1075 for (i = 0; i <= 9; i++)
1076 fmt->service_lines[0][i] =
1077 fmt->service_lines[1][i] = 0;
1078 for (i = 22; i <= 23; i++)
1079 fmt->service_lines[0][i] =
1080 fmt->service_lines[1][i] = 0;
1081 }
1082
1083 /* Now set the lcr values according to the specified service */
1084 for (i = 6; i <= 23; i++) {
1085 lcr[i] = 0;
1086 for (x = 0; x <= 1; x++) {
1087 switch (fmt->service_lines[1-x][i]) {
1088 case 0:
1089 lcr[i] |= 0xf << (4 * x);
1090 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001091 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001092 lcr[i] |= 1 << (4 * x);
1093 break;
1094 case V4L2_SLICED_CAPTION_525:
1095 lcr[i] |= 4 << (4 * x);
1096 break;
1097 case V4L2_SLICED_WSS_625:
1098 lcr[i] |= 5 << (4 * x);
1099 break;
1100 case V4L2_SLICED_VPS:
1101 lcr[i] |= 7 << (4 * x);
1102 break;
1103 }
1104 }
1105 }
1106 }
1107
1108 /* write the lcr registers */
1109 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001110 saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001111 }
1112
1113 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001114 saa711x_writeregs(client, fmt->service_set == 0 ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001115 saa7115_cfg_vbi_on :
1116 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001117}
1118
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001119static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001120{
1121 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001122 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001123 0, V4L2_SLICED_CAPTION_525, /* 4 */
1124 V4L2_SLICED_WSS_625, 0, /* 5 */
1125 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1126 0, 0, 0, 0
1127 };
1128 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1129 int i;
1130
1131 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1132 return -EINVAL;
1133 memset(sliced, 0, sizeof(*sliced));
1134 /* done if using raw VBI */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001135 if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001136 return 0;
1137 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001138 u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001139
1140 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1141 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1142 sliced->service_set |=
1143 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1144 }
1145 return 0;
1146}
1147
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001148static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1149{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001150 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001151 saa711x_set_lcr(client, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001152 return 0;
1153 }
1154 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1155 return -EINVAL;
1156
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001157 return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001158}
1159
1160/* Decode the sliced VBI data stream as created by the saa7115.
1161 The format is described in the saa7115 datasheet in Tables 25 and 26
1162 and in Figure 33.
1163 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001164 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001165 code. */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001166static void saa711x_decode_vbi_line(struct i2c_client *client,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001167 struct v4l2_decode_vbi_line *vbi)
1168{
1169 static const char vbi_no_data_pattern[] = {
1170 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1171 };
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001172 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001173 u8 *p = vbi->p;
1174 u32 wss;
1175 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1176
1177 vbi->type = 0; /* mark result as a failure */
1178 id1 = p[2];
1179 id2 = p[3];
1180 /* Note: the field bit is inverted for 60 Hz video */
1181 if (state->std & V4L2_STD_525_60)
1182 id1 ^= 0x40;
1183
1184 /* Skip internal header, p now points to the start of the payload */
1185 p += 4;
1186 vbi->p = p;
1187
1188 /* calculate field and line number of the VBI packet (1-23) */
1189 vbi->is_second_field = ((id1 & 0x40) != 0);
1190 vbi->line = (id1 & 0x3f) << 3;
1191 vbi->line |= (id2 & 0x70) >> 4;
1192
1193 /* Obtain data type */
1194 id2 &= 0xf;
1195
1196 /* If the VBI slicer does not detect any signal it will fill up
1197 the payload buffer with 0xa0 bytes. */
1198 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1199 return;
1200
1201 /* decode payloads */
1202 switch (id2) {
1203 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001204 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001205 break;
1206 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001207 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001208 return;
1209 vbi->type = V4L2_SLICED_CAPTION_525;
1210 break;
1211 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001212 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001213 if (wss == -1)
1214 return;
1215 p[0] = wss & 0xff;
1216 p[1] = wss >> 8;
1217 vbi->type = V4L2_SLICED_WSS_625;
1218 break;
1219 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001220 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001221 return;
1222 vbi->type = V4L2_SLICED_VPS;
1223 break;
1224 default:
1225 return;
1226 }
1227}
1228
1229/* ============ SAA7115 AUDIO settings (end) ============= */
1230
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001231static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001232{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001233 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001234 int *iarg = arg;
1235
1236 /* ioctls to allow direct access to the saa7115 registers for testing */
1237 switch (cmd) {
1238 case VIDIOC_S_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001239 return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001240
1241 case VIDIOC_G_FMT:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001242 return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001243
1244 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001245 return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001246
1247 case VIDIOC_G_TUNER:
1248 {
1249 struct v4l2_tuner *vt = arg;
1250 int status;
1251
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001252 if (state->radio)
1253 break;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001254 status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001255
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001256 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001257 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1258 break;
1259 }
1260
1261 case VIDIOC_LOG_STATUS:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001262 saa711x_log_status(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001263 break;
1264
1265 case VIDIOC_G_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001266 return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001267
1268 case VIDIOC_S_CTRL:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001269 return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001270
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001271 case VIDIOC_QUERYCTRL:
1272 {
1273 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001274
Hans Verkuil18318e02006-06-18 14:49:52 -03001275 switch (qc->id) {
1276 case V4L2_CID_BRIGHTNESS:
1277 case V4L2_CID_CONTRAST:
1278 case V4L2_CID_SATURATION:
1279 case V4L2_CID_HUE:
1280 return v4l2_ctrl_query_fill_std(qc);
1281 default:
1282 return -EINVAL;
1283 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001284 }
1285
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001286 case VIDIOC_G_STD:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001287 *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001288 break;
1289
1290 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001291 state->radio = 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001292 saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001293 break;
1294
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001295 case AUDC_SET_RADIO:
1296 state->radio = 1;
1297 break;
1298
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001299 case VIDIOC_INT_G_VIDEO_ROUTING:
1300 {
1301 struct v4l2_routing *route = arg;
1302
1303 route->input = state->input;
1304 route->output = 0;
1305 break;
1306 }
1307
1308 case VIDIOC_INT_S_VIDEO_ROUTING:
1309 {
1310 struct v4l2_routing *route = arg;
1311
1312 v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
1313 /* saa7113 does not have these inputs */
1314 if (state->ident == V4L2_IDENT_SAA7113 &&
1315 (route->input == SAA7115_COMPOSITE4 ||
1316 route->input == SAA7115_COMPOSITE5)) {
1317 return -EINVAL;
1318 }
1319 if (route->input > SAA7115_SVIDEO3)
1320 return -EINVAL;
1321 if (state->input == route->input)
1322 break;
1323 v4l_dbg(1, debug, client, "now setting %s input\n",
1324 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
1325 state->input = route->input;
1326
1327 /* select mode */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001328 saa711x_write(client, R_02_INPUT_CNTL_1,
1329 (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001330 state->input);
1331
1332 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001333 saa711x_write(client, R_09_LUMA_CNTL,
1334 (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001335 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1336 break;
1337 }
1338
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001339 case VIDIOC_STREAMON:
1340 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001341 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001342 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1343
1344 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1345 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001346 saa711x_write(client,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001347 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1348 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001349 }
1350 break;
1351
Hans Verkuilb7f82922006-04-02 12:50:42 -03001352 case VIDIOC_INT_S_CRYSTAL_FREQ:
1353 {
1354 struct v4l2_crystal_freq *freq = arg;
1355
1356 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1357 freq->freq != SAA7115_FREQ_24_576_MHZ)
1358 return -EINVAL;
1359 state->crystal_freq = freq->freq;
1360 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1361 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1362 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001363 saa711x_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001364 break;
1365 }
1366
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001367 case VIDIOC_INT_DECODE_VBI_LINE:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001368 saa711x_decode_vbi_line(client, arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001369 break;
1370
1371 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001372 v4l_dbg(1, debug, client, "decoder RESET\n");
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001373 saa711x_writeregs(client, saa7115_cfg_reset_scaler);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001374 break;
1375
1376 case VIDIOC_INT_G_VBI_DATA:
1377 {
1378 struct v4l2_sliced_vbi_data *data = arg;
1379
1380 switch (data->id) {
1381 case V4L2_SLICED_WSS_625:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001382 if (saa711x_read(client, 0x6b) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001383 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001384 data->data[0] = saa711x_read(client, 0x6c);
1385 data->data[1] = saa711x_read(client, 0x6d);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001386 return 0;
1387 case V4L2_SLICED_CAPTION_525:
1388 if (data->field == 0) {
1389 /* CC */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001390 if (saa711x_read(client, 0x66) & 0xc0)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001391 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001392 data->data[0] = saa711x_read(client, 0x67);
1393 data->data[1] = saa711x_read(client, 0x68);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001394 return 0;
1395 }
1396 /* XDS */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001397 if (saa711x_read(client, 0x66) & 0x30)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001398 return -EIO;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001399 data->data[0] = saa711x_read(client, 0x69);
1400 data->data[1] = saa711x_read(client, 0x6a);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001401 return 0;
1402 default:
1403 return -EINVAL;
1404 }
1405 break;
1406 }
1407
1408#ifdef CONFIG_VIDEO_ADV_DEBUG
1409 case VIDIOC_INT_G_REGISTER:
1410 {
1411 struct v4l2_register *reg = arg;
1412
1413 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1414 return -EINVAL;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001415 reg->val = saa711x_read(client, reg->reg & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001416 break;
1417 }
1418
1419 case VIDIOC_INT_S_REGISTER:
1420 {
1421 struct v4l2_register *reg = arg;
1422
1423 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1424 return -EINVAL;
1425 if (!capable(CAP_SYS_ADMIN))
1426 return -EPERM;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001427 saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001428 break;
1429 }
1430#endif
1431
1432 case VIDIOC_INT_G_CHIP_IDENT:
1433 *iarg = state->ident;
1434 break;
1435
1436 default:
1437 return -EINVAL;
1438 }
1439
1440 return 0;
1441}
1442
1443/* ----------------------------------------------------------------------- */
1444
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001445static struct i2c_driver i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001446
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001447static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001448{
1449 struct i2c_client *client;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001450 struct saa711x_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001451 int i;
1452 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001453 u8 chip_id;
1454
1455 /* Check if the adapter supports the needed features */
1456 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1457 return 0;
1458
Panagiotis Issaris74081872006-01-11 19:40:56 -02001459 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001460 if (client == 0)
1461 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001462 client->addr = address;
1463 client->adapter = adapter;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001464 client->driver = &i2c_driver_saa711x;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001465 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1466
Hans Verkuild0d30c02006-11-25 09:45:50 -03001467 for (i = 0; i < 0x0f; i++) {
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001468 saa711x_write(client, 0, i);
Hans Verkuild0d30c02006-11-25 09:45:50 -03001469 name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
1470 if (name[i] > '9')
1471 name[i] += 'a' - '9' - 1;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001472 }
Hans Verkuild0d30c02006-11-25 09:45:50 -03001473 name[i] = '\0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001474
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001475 saa711x_write(client, 0, 5);
1476 chip_id = saa711x_read(client, 0) & 0x0f;
Mauro Carvalho Chehab3e7d3e52006-09-01 18:39:05 -03001477
Hans Verkuilf7668162006-11-25 09:40:28 -03001478 /* Check whether this chip is part of the saa711x series */
1479 if (memcmp(name, "1f711", 5)) {
1480 v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
1481 address << 1, name);
1482 return 0;
1483 }
1484
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001485 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001486 v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001487
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001488 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001489 i2c_set_clientdata(client, state);
1490 if (state == NULL) {
1491 kfree(client);
1492 return -ENOMEM;
1493 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001494 state->input = -1;
1495 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001496 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001497 state->bright = 128;
1498 state->contrast = 64;
1499 state->hue = 0;
1500 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001501 switch (chip_id) {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001502 case 1:
1503 state->ident = V4L2_IDENT_SAA7111;
1504 break;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001505 case 3:
1506 state->ident = V4L2_IDENT_SAA7113;
1507 break;
1508 case 4:
1509 state->ident = V4L2_IDENT_SAA7114;
1510 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001511 case 5:
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001512 state->ident = V4L2_IDENT_SAA7115;
1513 break;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001514 case 8:
1515 state->ident = V4L2_IDENT_SAA7118;
1516 break;
1517 default:
1518 state->ident = V4L2_IDENT_SAA7111;
1519 v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
1520
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001521 }
1522
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001523 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001524
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001525 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001526
1527 /* init to 60hz/48khz */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001528 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
1529 switch (state->ident) {
1530 case V4L2_IDENT_SAA7111:
1531 saa711x_writeregs(client, saa7111_init);
1532 break;
1533 case V4L2_IDENT_SAA7113:
1534 saa711x_writeregs(client, saa7113_init);
1535 break;
1536 default:
Hans Verkuilb7f82922006-04-02 12:50:42 -03001537 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001538 saa711x_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001539 }
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001540 saa711x_writeregs(client, saa7115_init_misc);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -03001541 saa711x_set_v4lstd(client, V4L2_STD_NTSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001542
1543 i2c_attach_client(client);
1544
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001545 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001546 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 -08001547
1548 return 0;
1549}
1550
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001551static int saa711x_probe(struct i2c_adapter *adapter)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001552{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001553 if (adapter->class & I2C_CLASS_TV_ANALOG)
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001554 return i2c_probe(adapter, &addr_data, &saa711x_attach);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001555 return 0;
1556}
1557
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001558static int saa711x_detach(struct i2c_client *client)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001559{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001560 struct saa711x_state *state = i2c_get_clientdata(client);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001561 int err;
1562
1563 err = i2c_detach_client(client);
1564 if (err) {
1565 return err;
1566 }
1567
1568 kfree(state);
1569 kfree(client);
1570 return 0;
1571}
1572
1573/* ----------------------------------------------------------------------- */
1574
1575/* i2c implementation */
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001576static struct i2c_driver i2c_driver_saa711x = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001577 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001578 .name = "saa7115",
1579 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001580 .id = I2C_DRIVERID_SAA711X,
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001581 .attach_adapter = saa711x_probe,
1582 .detach_client = saa711x_detach,
1583 .command = saa711x_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001584};
1585
1586
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001587static int __init saa711x_init_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001588{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001589 return i2c_add_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001590}
1591
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001592static void __exit saa711x_cleanup_module(void)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001593{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001594 i2c_del_driver(&i2c_driver_saa711x);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001595}
1596
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001597module_init(saa711x_init_module);
1598module_exit(saa711x_cleanup_module);