blob: d5052dbd074470312f7cea3270628d6afe789194 [file] [log] [blame]
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
Hans Verkuile19b2fc2005-11-13 16:08:04 -08002 *
3 * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
4 * the saa7111 driver by Dave Perks.
5 *
6 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
7 * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
8 *
9 * Slight changes for video timing and attachment output by
10 * Wolfgang Scherr <scherr@net4you.net>
11 *
12 * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
13 * by Ronald Bultje <rbultje@ronald.bitfreak.net>
14 *
15 * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
16 * (2/17/2003)
17 *
18 * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030019 * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080020 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version 2
24 * of the License, or (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
34 */
35
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -030036#include "saa711x_regs.h"
Hans Verkuile19b2fc2005-11-13 16:08:04 -080037
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/slab.h>
41#include <linux/i2c.h>
42#include <linux/videodev2.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080043#include <media/v4l2-common.h>
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -030044#include <media/saa7115.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020045#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080046
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030047MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
48MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
49 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080050MODULE_LICENSE("GPL");
51
52static int debug = 0;
Hans Verkuilfac9e892006-01-09 15:32:40 -020053module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080054
55MODULE_PARM_DESC(debug, "Debug level (0-1)");
56
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030057static unsigned short normal_i2c[] = {
Hans Verkuil01342352006-03-25 08:19:47 -030058 0x4a >> 1, 0x48 >> 1, /* SAA7113 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030059 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */
60 I2C_CLIENT_END };
Hans Verkuile19b2fc2005-11-13 16:08:04 -080061
62
63I2C_CLIENT_INSMOD;
64
65struct saa7115_state {
66 v4l2_std_id std;
67 int input;
68 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020069 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080070 int bright;
71 int contrast;
72 int hue;
73 int sat;
74 enum v4l2_chip_ident ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020075 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030076 u32 crystal_freq;
77 u8 ucgc;
78 u8 cgcdiv;
79 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080080};
81
82/* ----------------------------------------------------------------------- */
83
84static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
85{
86 return i2c_smbus_write_byte_data(client, reg, value);
87}
88
89static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
90{
91 unsigned char reg, data;
92
93 while (*regs != 0x00) {
94 reg = *(regs++);
95 data = *(regs++);
96 if (saa7115_write(client, reg, data) < 0)
97 return -1;
98 }
99 return 0;
100}
101
102static inline int saa7115_read(struct i2c_client *client, u8 reg)
103{
104 return i2c_smbus_read_byte_data(client, reg);
105}
106
107/* ----------------------------------------------------------------------- */
108
109/* If a value differs from the Hauppauge driver values, then the comment starts with
110 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
111 Hauppauge driver sets. */
112
113static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300114 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300115 R_01_INC_DELAY, 0x48, /* white peak control disabled */
116 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
117 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
118 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300119 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300120 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
121 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
122 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
123 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
124 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
125 R_0D_CHROMA_HUE_CNTL, 0x00,
126 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
127 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
128 R_11_MODE_DELAY_CNTL, 0x00,
129 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
130 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
131 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
132 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
133 R_19_RAW_DATA_OFF_CNTL, 0x80,
134 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
135 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
136 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
137 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300138
139 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300140 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
141 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800142 0x00, 0x00
143};
144
145static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300146 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
147 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
148 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
149 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800150 0x00, 0x00
151};
152
153/* ============== SAA7715 VIDEO templates ============= */
154
155static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300156 /* hsize = 0x2d0 = 720 */
157 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
158 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800159
160 /* Why not in 60hz-Land, too? */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300161 R_D0_B_HORIZ_PRESCALING, 0x01, /* downscale = 1 */
162 /* hor lum scaling 0x0400 = 1 */
163 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
164 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
165
166 /* must be hor lum scaling / 2 */
167 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
168 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800169
170 0x00, 0x00
171};
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300172
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800173static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300174 /* output window size = 248 (but 60hz is 240?) */
175 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8,
176 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800177
178 /* Why not in 60hz-Land, too? */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300179 R_D5_B_LUMA_CONTRAST_CNTL, 0x40, /* Lum contrast, nominal value = 0x40 */
180 R_D6_B_CHROMA_SATURATION_CNTL, 0x40, /* Chroma satur. nominal value = 0x80 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800181
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300182 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
183 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
184
185 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
186 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800187
188 0x00, 0x00
189};
190
191static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300192 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
193 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800194
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300195 R_15_VGATE_START_FID_CHG, 0x03,
196 R_16_VGATE_STOP, 0x11,
197 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800198
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300199 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
200 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800201
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300202 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800203
204 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300205 R_90_A_TASK_HANDLING_CNTL, 0x80,
206 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
207 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
208 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
209
210 /* hoffset low (input), 0x0002 is minimum */
211 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
212 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
213
214 /* hsize low (input), 0x02d0 = 720 */
215 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
216 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
217
218 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
219 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
220
221 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
222 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
223
224 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
225 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
226
227 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
228 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800229
230 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300231 R_C0_B_TASK_HANDLING_CNTL, 0x00,
232 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
233 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
234 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800235
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300236 /* 0x0002 is minimum */
237 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
238 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800239
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300240 /* 0x02d0 = 720 */
241 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
242 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
243
244 /* vwindow start 0x12 = 18 */
245 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
246 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
247
248 /* vwindow length 0xf8 = 248 */
249 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0xf8,
250 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
251
252 /* hwindow 0x02d0 = 720 */
253 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
254 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
255
256 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
257 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
258 R_F5_PULSGEN_LINE_LENGTH, 0xad,
259 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
260
261 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
262 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
263 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
264 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
265 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800266 0x00, 0x00
267};
268
269static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300270 /* hsize low (output), 720 same as 60hz */
271 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
272 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800273
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300274 R_D0_B_HORIZ_PRESCALING, 0x01, /* down scale = 1 */
275 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00, /* hor lum scaling 0x0400 = 1 */
276 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
277
278 /* must be hor lum scaling / 2 */
279 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
280 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800281
282 0x00, 0x00
283};
284static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300285 /* vsize low (output), 0x0120 = 288 */
286 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
287 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800288
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300289 R_D5_B_LUMA_CONTRAST_CNTL, 0x40, /* Lum contrast, nominal value = 0x40 */
290 R_D6_B_CHROMA_SATURATION_CNTL, 0x40, /* Chroma satur. nominal value = 0x80 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800291
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300292 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
293 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
294
295 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
296 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800297
298 0x00, 0x00
299};
300
301static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300302 R_80_GLOBAL_CNTL_1, 0x00,
303 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800304
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300305 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
306 R_16_VGATE_STOP, 0x16,
307 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800308
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300309 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
310 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800311
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300312 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800313
314 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300315 R_90_A_TASK_HANDLING_CNTL, 0x81,
316 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
317 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
318 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
319
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800320 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
321 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300322 /* hoffset low (input), 0x0002 is minimum */
323 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
324 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
325
326 /* hsize low (input), 0x02d0 = 720 */
327 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
328 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
329
330 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
331 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
332
333 /* vsize 0x12 = 18 */
334 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
335 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
336
337 /* hsize 0x05a0 = 1440 */
338 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
339 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
340 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
341 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800342
343 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300344 R_C0_B_TASK_HANDLING_CNTL, 0x00,
345 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
346 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
347 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800348
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300349 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
350 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
351 /* hoffset low (input), 0x0002 is minimum. See comment above. */
352 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
353 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800354
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300355 /* hsize 0x02d0 = 720 */
356 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
357 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
358
359 /* voffset 0x16 = 22 */
360 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
361 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
362
363 /* vsize 0x0120 = 288 */
364 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
365 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
366
367 /* hsize 0x02d0 = 720 */
368 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
369 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
370
371 /* vsize 0x0120 = 288 */
372 R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20,
373 R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01,
374
375 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
376 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
377 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
378 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
379
380 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */
381 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler (was 0xD0) */
382 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
383 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
384 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
385
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800386 0x00, 0x00
387};
388
389/* ============== SAA7715 VIDEO templates (end) ======= */
390
391static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300392 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
393 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
394 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
395 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
396 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
397
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800398 0x00, 0x00
399};
400
401static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300402 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
403 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
404 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
405 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
406 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
407
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800408 0x00, 0x00
409};
410
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300411static const unsigned char saa7113_init_auto_input[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300412 R_01_INC_DELAY, 0x08,
413 R_02_INPUT_CNTL_1, 0xc2,
414 R_03_INPUT_CNTL_2, 0x30,
415 R_04_INPUT_CNTL_3, 0x00,
416 R_05_INPUT_CNTL_4, 0x00,
417 R_06_H_SYNC_START, 0x89,
418 R_07_H_SYNC_STOP, 0x0d,
419 R_08_SYNC_CNTL, 0x88,
420 R_09_LUMA_CNTL, 0x01,
421 R_0A_LUMA_BRIGHT_CNTL, 0x80,
422 R_0B_LUMA_CONTRAST_CNTL, 0x47,
423 R_0C_CHROMA_SAT_CNTL, 0x40,
424 R_0D_CHROMA_HUE_CNTL, 0x00,
425 R_0E_CHROMA_CNTL_1, 0x01,
426 R_0F_CHROMA_GAIN_CNTL, 0x2a,
427 R_10_CHROMA_CNTL_2, 0x08,
428 R_11_MODE_DELAY_CNTL, 0x0c,
429 R_12_RT_SIGNAL_CNTL, 0x07,
430 R_13_RT_X_PORT_OUT_CNTL, 0x00,
431 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
432 R_15_VGATE_START_FID_CHG, 0x00,
433 R_16_VGATE_STOP, 0x00,
434 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
435
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300436 0x00, 0x00
437};
438
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800439static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300440 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
441 0x82, 0x00, /* Reserved register - value should be zero*/
442 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
443 R_84_I_PORT_SIGNAL_DEF, 0x20,
444 R_85_I_PORT_SIGNAL_POLAR, 0x21,
445 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
446 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800447
448 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300449 R_A0_A_HORIZ_PRESCALING, 0x01,
450 R_A1_A_ACCUMULATION_LENGTH, 0x00,
451 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800452
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300453 /* Configure controls at nominal value*/
454 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
455 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
456 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
457
458 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
459 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
460 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
461
462 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
463
464 /* must be horiz lum scaling / 2 */
465 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
466 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
467
468 /* must be offset luma / 2 */
469 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
470
471 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
472 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
473
474 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
475 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
476
477 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
478
479 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
480 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
481 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
482 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
483
484 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
485 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
486 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
487 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800488
489 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300490 R_D0_B_HORIZ_PRESCALING, 0x01,
491 R_D1_B_ACCUMULATION_LENGTH, 0x00,
492 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800493
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300494 /* Configure controls at nominal value*/
495 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
496 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
497 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800498
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300499 /* hor lum scaling 0x0400 = 1 */
500 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
501 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
502
503 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
504
505 /* must be hor lum scaling / 2 */
506 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
507 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
508
509 /* must be offset luma / 2 */
510 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
511
512 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
513 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
514
515 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
516 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
517
518 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
519
520 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
521 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
522 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
523 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
524
525 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
526 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
527 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
528 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
529
530 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
531 R_F3_PLL_INCREMENT, 0x46,
532 R_F4_PLL2_STATUS, 0x00,
533 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
534 R_F8_PULSE_B_POS, 0x00,
535 R_F9_PULSE_B_POS_MSB, 0x4b,
536 R_FA_PULSE_C_POS, 0x00,
537 R_FB_PULSE_C_POS_MSB, 0x4b,
538
539 /* PLL2 lock detection settings: 71 lines 50% phase error */
540 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800541
542 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300543 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
544 R_41_LCR_BASE, 0xff,
545 R_41_LCR_BASE+1, 0xff,
546 R_41_LCR_BASE+2, 0xff,
547 R_41_LCR_BASE+3, 0xff,
548 R_41_LCR_BASE+4, 0xff,
549 R_41_LCR_BASE+5, 0xff,
550 R_41_LCR_BASE+6, 0xff,
551 R_41_LCR_BASE+7, 0xff,
552 R_41_LCR_BASE+8, 0xff,
553 R_41_LCR_BASE+9, 0xff,
554 R_41_LCR_BASE+10, 0xff,
555 R_41_LCR_BASE+11, 0xff,
556 R_41_LCR_BASE+12, 0xff,
557 R_41_LCR_BASE+13, 0xff,
558 R_41_LCR_BASE+14, 0xff,
559 R_41_LCR_BASE+15, 0xff,
560 R_41_LCR_BASE+16, 0xff,
561 R_41_LCR_BASE+17, 0xff,
562 R_41_LCR_BASE+18, 0xff,
563 R_41_LCR_BASE+19, 0xff,
564 R_41_LCR_BASE+20, 0xff,
565 R_41_LCR_BASE+21, 0xff,
566 R_41_LCR_BASE+22, 0xff,
567 R_58_PROGRAM_FRAMING_CODE, 0x40,
568 R_59_H_OFF_FOR_SLICER, 0x47,
569 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
570 R_5D_DID, 0xbd,
571 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800572
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300573 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
574 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800575
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300576 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
577 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
578 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800579 0x00, 0x00
580};
581
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800582static int saa7115_odd_parity(u8 c)
583{
584 c ^= (c >> 4);
585 c ^= (c >> 2);
586 c ^= (c >> 1);
587
588 return c & 1;
589}
590
591static int saa7115_decode_vps(u8 * dst, u8 * p)
592{
593 static const u8 biphase_tbl[] = {
594 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
595 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
596 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
597 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
598 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
599 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
600 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
601 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
602 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
603 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
604 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
605 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
606 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
607 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
608 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
609 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
610 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
611 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
612 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
613 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
614 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
615 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
616 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
617 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
618 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
619 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
620 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
621 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
622 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
623 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
624 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
625 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
626 };
627 int i;
628 u8 c, err = 0;
629
630 for (i = 0; i < 2 * 13; i += 2) {
631 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
632 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
633 dst[i / 2] = c;
634 }
635 return err & 0xf0;
636}
637
638static int saa7115_decode_wss(u8 * p)
639{
640 static const int wss_bits[8] = {
641 0, 0, 0, 1, 0, 1, 1, 1
642 };
643 unsigned char parity;
644 int wss = 0;
645 int i;
646
647 for (i = 0; i < 16; i++) {
648 int b1 = wss_bits[p[i] & 7];
649 int b2 = wss_bits[(p[i] >> 3) & 7];
650
651 if (b1 == b2)
652 return -1;
653 wss |= b2 << i;
654 }
655 parity = wss & 15;
656 parity ^= parity >> 2;
657 parity ^= parity >> 1;
658
659 if (!(parity & 1))
660 return -1;
661
662 return wss;
663}
664
665
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200666static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800667{
668 struct saa7115_state *state = i2c_get_clientdata(client);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200669 u32 acpf;
670 u32 acni;
671 u32 hz;
672 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300673 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800674
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200675 v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200676
677 /* sanity check */
678 if (freq < 32000 || freq > 48000)
679 return -EINVAL;
680
Hans Verkuilb7f82922006-04-02 12:50:42 -0300681 /* The saa7113 has no audio clock */
682 if (state->ident == V4L2_IDENT_SAA7113)
683 return 0;
684
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200685 /* hz is the refresh rate times 100 */
686 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
687 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
688 acpf = (25600 * freq) / hz;
689 /* acni = (256 * freq * 2^23) / crystal_frequency =
690 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300691 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200692 f = freq;
693 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300694 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200695 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300696 if (state->ucgc) {
697 acpf = acpf * state->cgcdiv / 16;
698 acni = acni * state->cgcdiv / 16;
699 acc = 0x80;
700 if (state->cgcdiv == 3)
701 acc |= 0x40;
702 }
703 if (state->apll)
704 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200705
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300706 saa7115_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
707 saa7115_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
708 saa7115_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
709
710 saa7115_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
711 saa7115_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
712 (acpf >> 8) & 0xff);
713 saa7115_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
714 (acpf >> 16) & 0x03);
715
716 saa7115_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
717 saa7115_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
718 saa7115_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800719 state->audclk_freq = freq;
720 return 0;
721}
722
723static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
724{
725 struct saa7115_state *state = i2c_get_clientdata(client);
726
727 switch (ctrl->id) {
728 case V4L2_CID_BRIGHTNESS:
729 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200730 v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800731 return -ERANGE;
732 }
733
734 state->bright = ctrl->value;
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300735 saa7115_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800736 break;
737
738 case V4L2_CID_CONTRAST:
739 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200740 v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800741 return -ERANGE;
742 }
743
744 state->contrast = ctrl->value;
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300745 saa7115_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800746 break;
747
748 case V4L2_CID_SATURATION:
749 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200750 v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800751 return -ERANGE;
752 }
753
754 state->sat = ctrl->value;
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300755 saa7115_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800756 break;
757
758 case V4L2_CID_HUE:
759 if (ctrl->value < -127 || ctrl->value > 127) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200760 v4l_err(client, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800761 return -ERANGE;
762 }
763
764 state->hue = ctrl->value;
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300765 saa7115_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800766 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200767
768 default:
769 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800770 }
771
772 return 0;
773}
774
775static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
776{
777 struct saa7115_state *state = i2c_get_clientdata(client);
778
779 switch (ctrl->id) {
780 case V4L2_CID_BRIGHTNESS:
781 ctrl->value = state->bright;
782 break;
783 case V4L2_CID_CONTRAST:
784 ctrl->value = state->contrast;
785 break;
786 case V4L2_CID_SATURATION:
787 ctrl->value = state->sat;
788 break;
789 case V4L2_CID_HUE:
790 ctrl->value = state->hue;
791 break;
792 default:
793 return -EINVAL;
794 }
795
796 return 0;
797}
798
799static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
800{
801 struct saa7115_state *state = i2c_get_clientdata(client);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300802 int taskb = saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800803
Hans Verkuil30b54d52006-01-09 15:25:43 -0200804 /* Prevent unnecessary standard changes. During a standard
805 change the I-Port is temporarily disabled. Any devices
806 reading from that port can get confused.
807 Note that VIDIOC_S_STD is also used to switch from
808 radio to TV mode, so if a VIDIOC_S_STD is broadcast to
809 all I2C devices then you do not want to have an unwanted
810 side-effect here. */
811 if (std == state->std)
812 return;
813
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800814 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
815 if (std & V4L2_STD_525_60) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200816 v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800817 saa7115_writeregs(client, saa7115_cfg_60hz_video);
818 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -0200819 v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800820 saa7115_writeregs(client, saa7115_cfg_50hz_video);
821 }
822
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300823 /* Register 0E - Bits D6-D4 on NO-AUTO mode
824 (SAA7113 doesn't have auto mode)
825 50 Hz / 625 lines 60 Hz / 525 lines
826 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
827 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
828 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
829 011 NTSC N (3.58MHz) PAL M (3.58MHz)
830 100 reserved NTSC-Japan (3.58MHz)
831 */
832 if (state->ident == V4L2_IDENT_SAA7113) {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300833 u8 reg = saa7115_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300834
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300835 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300836 reg |= 0x30;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300837 } else if (std == V4L2_STD_PAL_N) {
Hans Verkuil01342352006-03-25 08:19:47 -0300838 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300839 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300840 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300841 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300842 reg |= 0x40;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300843 }
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300844 saa7115_write(client, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300845 }
846
847
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800848 state->std = std;
849
850 /* restart task B if needed */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300851 if (taskb && state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800852 saa7115_writeregs(client, saa7115_cfg_vbi_on);
853 }
854
855 /* switch audio mode too! */
856 saa7115_set_audio_clock_freq(client, state->audclk_freq);
857}
858
859static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
860{
861 struct saa7115_state *state = i2c_get_clientdata(client);
862
863 return state->std;
864}
865
866static void saa7115_log_status(struct i2c_client *client)
867{
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800868 struct saa7115_state *state = i2c_get_clientdata(client);
869 int reg1e, reg1f;
870 int signalOk;
871 int vcr;
872
Hans Verkuilfac9e892006-01-09 15:32:40 -0200873 v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300874 if (state->ident != V4L2_IDENT_SAA7115) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800875 /* status for the saa7114 */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300876 reg1f = saa7115_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800877 signalOk = (reg1f & 0xc1) == 0x81;
Hans Verkuilfac9e892006-01-09 15:32:40 -0200878 v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
879 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800880 return;
881 }
882
883 /* status for the saa7115 */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300884 reg1e = saa7115_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
885 reg1f = saa7115_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800886
887 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
888 vcr = !(reg1f & 0x10);
889
Hans Verkuil21fa7152006-01-09 15:25:41 -0200890 if (state->input >= 6) {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200891 v4l_info(client, "Input: S-Video %d\n", state->input - 6);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200892 } else {
Hans Verkuilfac9e892006-01-09 15:32:40 -0200893 v4l_info(client, "Input: Composite %d\n", state->input);
Hans Verkuil21fa7152006-01-09 15:25:41 -0200894 }
Hans Verkuilfac9e892006-01-09 15:32:40 -0200895 v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
896 v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800897
898 switch (reg1e & 0x03) {
899 case 1:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200900 v4l_info(client, "Detected format: NTSC\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800901 break;
902 case 2:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200903 v4l_info(client, "Detected format: PAL\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800904 break;
905 case 3:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200906 v4l_info(client, "Detected format: SECAM\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800907 break;
908 default:
Hans Verkuilfac9e892006-01-09 15:32:40 -0200909 v4l_info(client, "Detected format: BW/No color\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800910 break;
911 }
912}
913
914/* setup the sliced VBI lcr registers according to the sliced VBI format */
915static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
916{
917 struct saa7115_state *state = i2c_get_clientdata(client);
918 int is_50hz = (state->std & V4L2_STD_625_50);
919 u8 lcr[24];
920 int i, x;
921
Hans Verkuil01342352006-03-25 08:19:47 -0300922 /* saa7113/7114 doesn't yet support VBI */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300923 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800924 return;
925
926 for (i = 0; i <= 23; i++)
927 lcr[i] = 0xff;
928
929 if (fmt->service_set == 0) {
930 /* raw VBI */
931 if (is_50hz)
932 for (i = 6; i <= 23; i++)
933 lcr[i] = 0xdd;
934 else
935 for (i = 10; i <= 21; i++)
936 lcr[i] = 0xdd;
937 } else {
938 /* sliced VBI */
939 /* first clear lines that cannot be captured */
940 if (is_50hz) {
941 for (i = 0; i <= 5; i++)
942 fmt->service_lines[0][i] =
943 fmt->service_lines[1][i] = 0;
944 }
945 else {
946 for (i = 0; i <= 9; i++)
947 fmt->service_lines[0][i] =
948 fmt->service_lines[1][i] = 0;
949 for (i = 22; i <= 23; i++)
950 fmt->service_lines[0][i] =
951 fmt->service_lines[1][i] = 0;
952 }
953
954 /* Now set the lcr values according to the specified service */
955 for (i = 6; i <= 23; i++) {
956 lcr[i] = 0;
957 for (x = 0; x <= 1; x++) {
958 switch (fmt->service_lines[1-x][i]) {
959 case 0:
960 lcr[i] |= 0xf << (4 * x);
961 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -0300962 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800963 lcr[i] |= 1 << (4 * x);
964 break;
965 case V4L2_SLICED_CAPTION_525:
966 lcr[i] |= 4 << (4 * x);
967 break;
968 case V4L2_SLICED_WSS_625:
969 lcr[i] |= 5 << (4 * x);
970 break;
971 case V4L2_SLICED_VPS:
972 lcr[i] |= 7 << (4 * x);
973 break;
974 }
975 }
976 }
977 }
978
979 /* write the lcr registers */
980 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300981 saa7115_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800982 }
983
984 /* enable/disable raw VBI capturing */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300985 saa7115_writeregs(client, fmt->service_set == 0 ?
986 saa7115_cfg_vbi_on :
987 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800988}
989
990static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
991{
992 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -0300993 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800994 0, V4L2_SLICED_CAPTION_525, /* 4 */
995 V4L2_SLICED_WSS_625, 0, /* 5 */
996 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
997 0, 0, 0, 0
998 };
999 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1000 int i;
1001
1002 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1003 return -EINVAL;
1004 memset(sliced, 0, sizeof(*sliced));
1005 /* done if using raw VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001006 if (saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001007 return 0;
1008 for (i = 2; i <= 23; i++) {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001009 u8 v = saa7115_read(client, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001010
1011 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1012 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1013 sliced->service_set |=
1014 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1015 }
1016 return 0;
1017}
1018
1019static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
1020{
1021 struct saa7115_state *state = i2c_get_clientdata(client);
1022 struct v4l2_pix_format *pix;
1023 int HPSC, HFSC;
1024 int VSCY, Vsrc;
1025 int is_50hz = state->std & V4L2_STD_625_50;
1026
1027 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
1028 saa7115_set_lcr(client, &fmt->fmt.sliced);
1029 return 0;
1030 }
1031 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1032 return -EINVAL;
1033
1034 pix = &(fmt->fmt.pix);
1035
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001036 v4l_dbg(1, debug, client, "decoder set size\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001037
1038 /* FIXME need better bounds checking here */
1039 if ((pix->width < 1) || (pix->width > 1440))
1040 return -EINVAL;
1041 if ((pix->height < 1) || (pix->height > 960))
1042 return -EINVAL;
1043
1044 /* probably have a valid size, let's set it */
1045 /* Set output width/height */
1046 /* width */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001047 saa7115_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
1048 (u8) (pix->width & 0xff));
1049 saa7115_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
1050 (u8) ((pix->width >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001051 /* height */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001052 saa7115_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
1053 (u8) (pix->height & 0xff));
1054 saa7115_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
1055 (u8) ((pix->height >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001056
1057 /* Scaling settings */
1058 /* Hprescaler is floor(inres/outres) */
1059 /* FIXME hardcoding input res */
1060 if (pix->width != 720) {
1061 HPSC = (int)(720 / pix->width);
1062 /* 0 is not allowed (div. by zero) */
1063 HPSC = HPSC ? HPSC : 1;
1064 HFSC = (int)((1024 * 720) / (HPSC * pix->width));
1065
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001066 v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001067 /* FIXME hardcodes to "Task B"
1068 * write H prescaler integer */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001069 saa7115_write(client, R_D0_B_HORIZ_PRESCALING,
1070 (u8) (HPSC & 0x3f));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001071
1072 /* write H fine-scaling (luminance) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001073 saa7115_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
1074 (u8) (HFSC & 0xff));
1075 saa7115_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
1076 (u8) ((HFSC >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001077 /* write H fine-scaling (chrominance)
1078 * must be lum/2, so i'll just bitshift :) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001079 saa7115_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
1080 (u8) ((HFSC >> 1) & 0xff));
1081 saa7115_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
1082 (u8) ((HFSC >> 9) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001083 } else {
1084 if (is_50hz) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001085 v4l_dbg(1, debug, client, "Setting full 50hz width\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001086 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
1087 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001088 v4l_dbg(1, debug, client, "Setting full 60hz width\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001089 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
1090 }
1091 }
1092
1093 Vsrc = is_50hz ? 576 : 480;
1094
1095 if (pix->height != Vsrc) {
1096 VSCY = (int)((1024 * Vsrc) / pix->height);
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001097 v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001098
1099 /* Correct Contrast and Luminance */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001100 saa7115_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
1101 (u8) (64 * 1024 / VSCY));
1102 saa7115_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
1103 (u8) (64 * 1024 / VSCY));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001104
1105 /* write V fine-scaling (luminance) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001106 saa7115_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
1107 (u8) (VSCY & 0xff));
1108 saa7115_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
1109 (u8) ((VSCY >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001110 /* write V fine-scaling (chrominance) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001111 saa7115_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
1112 (u8) (VSCY & 0xff));
1113 saa7115_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
1114 (u8) ((VSCY >> 8) & 0xff));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001115 } else {
1116 if (is_50hz) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001117 v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001118 saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
1119 } else {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001120 v4l_dbg(1, debug, client, "Setting full 60hz height\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001121 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
1122 }
1123 }
1124
1125 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1126 return 0;
1127}
1128
1129/* Decode the sliced VBI data stream as created by the saa7115.
1130 The format is described in the saa7115 datasheet in Tables 25 and 26
1131 and in Figure 33.
1132 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001133 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001134 code. */
1135static void saa7115_decode_vbi_line(struct i2c_client *client,
1136 struct v4l2_decode_vbi_line *vbi)
1137{
1138 static const char vbi_no_data_pattern[] = {
1139 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1140 };
1141 struct saa7115_state *state = i2c_get_clientdata(client);
1142 u8 *p = vbi->p;
1143 u32 wss;
1144 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1145
1146 vbi->type = 0; /* mark result as a failure */
1147 id1 = p[2];
1148 id2 = p[3];
1149 /* Note: the field bit is inverted for 60 Hz video */
1150 if (state->std & V4L2_STD_525_60)
1151 id1 ^= 0x40;
1152
1153 /* Skip internal header, p now points to the start of the payload */
1154 p += 4;
1155 vbi->p = p;
1156
1157 /* calculate field and line number of the VBI packet (1-23) */
1158 vbi->is_second_field = ((id1 & 0x40) != 0);
1159 vbi->line = (id1 & 0x3f) << 3;
1160 vbi->line |= (id2 & 0x70) >> 4;
1161
1162 /* Obtain data type */
1163 id2 &= 0xf;
1164
1165 /* If the VBI slicer does not detect any signal it will fill up
1166 the payload buffer with 0xa0 bytes. */
1167 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1168 return;
1169
1170 /* decode payloads */
1171 switch (id2) {
1172 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001173 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001174 break;
1175 case 4:
1176 if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
1177 return;
1178 vbi->type = V4L2_SLICED_CAPTION_525;
1179 break;
1180 case 5:
1181 wss = saa7115_decode_wss(p);
1182 if (wss == -1)
1183 return;
1184 p[0] = wss & 0xff;
1185 p[1] = wss >> 8;
1186 vbi->type = V4L2_SLICED_WSS_625;
1187 break;
1188 case 7:
1189 if (saa7115_decode_vps(p, p) != 0)
1190 return;
1191 vbi->type = V4L2_SLICED_VPS;
1192 break;
1193 default:
1194 return;
1195 }
1196}
1197
1198/* ============ SAA7115 AUDIO settings (end) ============= */
1199
1200static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
1201{
1202 struct saa7115_state *state = i2c_get_clientdata(client);
1203 int *iarg = arg;
1204
1205 /* ioctls to allow direct access to the saa7115 registers for testing */
1206 switch (cmd) {
1207 case VIDIOC_S_FMT:
1208 return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
1209
1210 case VIDIOC_G_FMT:
1211 return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
1212
1213 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001214 return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001215
1216 case VIDIOC_G_TUNER:
1217 {
1218 struct v4l2_tuner *vt = arg;
1219 int status;
1220
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001221 if (state->radio)
1222 break;
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001223 status = saa7115_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001224
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001225 v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001226 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1227 break;
1228 }
1229
1230 case VIDIOC_LOG_STATUS:
1231 saa7115_log_status(client);
1232 break;
1233
1234 case VIDIOC_G_CTRL:
1235 return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
1236
1237 case VIDIOC_S_CTRL:
1238 return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
1239
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001240 case VIDIOC_QUERYCTRL:
1241 {
1242 struct v4l2_queryctrl *qc = arg;
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001243
Hans Verkuil18318e02006-06-18 14:49:52 -03001244 switch (qc->id) {
1245 case V4L2_CID_BRIGHTNESS:
1246 case V4L2_CID_CONTRAST:
1247 case V4L2_CID_SATURATION:
1248 case V4L2_CID_HUE:
1249 return v4l2_ctrl_query_fill_std(qc);
1250 default:
1251 return -EINVAL;
1252 }
Hans Verkuilda4ae5a2006-01-09 15:32:41 -02001253 }
1254
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001255 case VIDIOC_G_STD:
1256 *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
1257 break;
1258
1259 case VIDIOC_S_STD:
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001260 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001261 saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
1262 break;
1263
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001264 case AUDC_SET_RADIO:
1265 state->radio = 1;
1266 break;
1267
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001268 case VIDIOC_INT_G_VIDEO_ROUTING:
1269 {
1270 struct v4l2_routing *route = arg;
1271
1272 route->input = state->input;
1273 route->output = 0;
1274 break;
1275 }
1276
1277 case VIDIOC_INT_S_VIDEO_ROUTING:
1278 {
1279 struct v4l2_routing *route = arg;
1280
1281 v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
1282 /* saa7113 does not have these inputs */
1283 if (state->ident == V4L2_IDENT_SAA7113 &&
1284 (route->input == SAA7115_COMPOSITE4 ||
1285 route->input == SAA7115_COMPOSITE5)) {
1286 return -EINVAL;
1287 }
1288 if (route->input > SAA7115_SVIDEO3)
1289 return -EINVAL;
1290 if (state->input == route->input)
1291 break;
1292 v4l_dbg(1, debug, client, "now setting %s input\n",
1293 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
1294 state->input = route->input;
1295
1296 /* select mode */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001297 saa7115_write(client, R_02_INPUT_CNTL_1,
1298 (saa7115_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001299 state->input);
1300
1301 /* bypass chrominance trap for S-Video modes */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001302 saa7115_write(client, R_09_LUMA_CNTL,
1303 (saa7115_read(client, R_09_LUMA_CNTL) & 0x7f) |
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -03001304 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1305 break;
1306 }
1307
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001308 case VIDIOC_STREAMON:
1309 case VIDIOC_STREAMOFF:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001310 v4l_dbg(1, debug, client, "%s output\n",
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001311 (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
1312
1313 if (state->enable != (cmd == VIDIOC_STREAMON)) {
1314 state->enable = (cmd == VIDIOC_STREAMON);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001315 saa7115_write(client,
1316 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
1317 state->enable);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001318 }
1319 break;
1320
Hans Verkuilb7f82922006-04-02 12:50:42 -03001321 case VIDIOC_INT_S_CRYSTAL_FREQ:
1322 {
1323 struct v4l2_crystal_freq *freq = arg;
1324
1325 if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
1326 freq->freq != SAA7115_FREQ_24_576_MHZ)
1327 return -EINVAL;
1328 state->crystal_freq = freq->freq;
1329 state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1330 state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1331 state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
1332 saa7115_set_audio_clock_freq(client, state->audclk_freq);
1333 break;
1334 }
1335
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001336 case VIDIOC_INT_DECODE_VBI_LINE:
1337 saa7115_decode_vbi_line(client, arg);
1338 break;
1339
1340 case VIDIOC_INT_RESET:
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001341 v4l_dbg(1, debug, client, "decoder RESET\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001342 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1343 break;
1344
1345 case VIDIOC_INT_G_VBI_DATA:
1346 {
1347 struct v4l2_sliced_vbi_data *data = arg;
1348
1349 switch (data->id) {
1350 case V4L2_SLICED_WSS_625:
1351 if (saa7115_read(client, 0x6b) & 0xc0)
1352 return -EIO;
1353 data->data[0] = saa7115_read(client, 0x6c);
1354 data->data[1] = saa7115_read(client, 0x6d);
1355 return 0;
1356 case V4L2_SLICED_CAPTION_525:
1357 if (data->field == 0) {
1358 /* CC */
1359 if (saa7115_read(client, 0x66) & 0xc0)
1360 return -EIO;
1361 data->data[0] = saa7115_read(client, 0x67);
1362 data->data[1] = saa7115_read(client, 0x68);
1363 return 0;
1364 }
1365 /* XDS */
1366 if (saa7115_read(client, 0x66) & 0x30)
1367 return -EIO;
1368 data->data[0] = saa7115_read(client, 0x69);
1369 data->data[1] = saa7115_read(client, 0x6a);
1370 return 0;
1371 default:
1372 return -EINVAL;
1373 }
1374 break;
1375 }
1376
1377#ifdef CONFIG_VIDEO_ADV_DEBUG
1378 case VIDIOC_INT_G_REGISTER:
1379 {
1380 struct v4l2_register *reg = arg;
1381
1382 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1383 return -EINVAL;
1384 reg->val = saa7115_read(client, reg->reg & 0xff);
1385 break;
1386 }
1387
1388 case VIDIOC_INT_S_REGISTER:
1389 {
1390 struct v4l2_register *reg = arg;
1391
1392 if (reg->i2c_id != I2C_DRIVERID_SAA711X)
1393 return -EINVAL;
1394 if (!capable(CAP_SYS_ADMIN))
1395 return -EPERM;
1396 saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
1397 break;
1398 }
1399#endif
1400
1401 case VIDIOC_INT_G_CHIP_IDENT:
1402 *iarg = state->ident;
1403 break;
1404
1405 default:
1406 return -EINVAL;
1407 }
1408
1409 return 0;
1410}
1411
1412/* ----------------------------------------------------------------------- */
1413
1414static struct i2c_driver i2c_driver_saa7115;
1415
1416static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
1417{
1418 struct i2c_client *client;
1419 struct saa7115_state *state;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001420 int i;
1421 char name[17];
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001422 u8 chip_id;
1423
1424 /* Check if the adapter supports the needed features */
1425 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1426 return 0;
1427
Panagiotis Issaris74081872006-01-11 19:40:56 -02001428 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001429 if (client == 0)
1430 return -ENOMEM;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001431 client->addr = address;
1432 client->adapter = adapter;
1433 client->driver = &i2c_driver_saa7115;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001434 snprintf(client->name, sizeof(client->name) - 1, "saa7115");
1435
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001436 v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001437
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001438 for (i=0;i<0x0f;i++) {
1439 saa7115_write(client, 0, i);
1440 name[i] = (saa7115_read(client, 0) &0x0f) +'0';
1441 if (name[i]>'9')
1442 name[i]+='a'-'9'-1;
1443 }
1444 name[i]='\0';
1445
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001446 saa7115_write(client, 0, 5);
1447 chip_id = saa7115_read(client, 0) & 0x0f;
Hans Verkuil01342352006-03-25 08:19:47 -03001448 if (chip_id < 3 && chip_id > 5) {
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001449 v4l_dbg(1, debug, client, "saa7115 not found\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001450 kfree(client);
1451 return 0;
1452 }
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001453 snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001454 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 -08001455
Panagiotis Issaris74081872006-01-11 19:40:56 -02001456 state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001457 i2c_set_clientdata(client, state);
1458 if (state == NULL) {
1459 kfree(client);
1460 return -ENOMEM;
1461 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001462 state->std = V4L2_STD_NTSC;
1463 state->input = -1;
1464 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001465 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001466 state->bright = 128;
1467 state->contrast = 64;
1468 state->hue = 0;
1469 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001470 switch (chip_id) {
1471 case 3:
1472 state->ident = V4L2_IDENT_SAA7113;
1473 break;
1474 case 4:
1475 state->ident = V4L2_IDENT_SAA7114;
1476 break;
1477 default:
1478 state->ident = V4L2_IDENT_SAA7115;
1479 break;
1480 }
1481
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001482 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001483
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001484 v4l_dbg(1, debug, client, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001485
1486 /* init to 60hz/48khz */
Hans Verkuilb7f82922006-04-02 12:50:42 -03001487 if (state->ident == V4L2_IDENT_SAA7113) {
1488 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001489 saa7115_writeregs(client, saa7113_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001490 } else {
1491 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001492 saa7115_writeregs(client, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001493 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001494 saa7115_writeregs(client, saa7115_init_misc);
1495 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
1496 saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
1497 saa7115_writeregs(client, saa7115_cfg_60hz_video);
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001498 saa7115_set_audio_clock_freq(client, state->audclk_freq);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001499 saa7115_writeregs(client, saa7115_cfg_reset_scaler);
1500
1501 i2c_attach_client(client);
1502
Mauro Carvalho Chehabf167cb4e2006-01-11 19:41:49 -02001503 v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001504 saa7115_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa7115_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001505
1506 return 0;
1507}
1508
1509static int saa7115_probe(struct i2c_adapter *adapter)
1510{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001511 if (adapter->class & I2C_CLASS_TV_ANALOG)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001512 return i2c_probe(adapter, &addr_data, &saa7115_attach);
1513 return 0;
1514}
1515
1516static int saa7115_detach(struct i2c_client *client)
1517{
1518 struct saa7115_state *state = i2c_get_clientdata(client);
1519 int err;
1520
1521 err = i2c_detach_client(client);
1522 if (err) {
1523 return err;
1524 }
1525
1526 kfree(state);
1527 kfree(client);
1528 return 0;
1529}
1530
1531/* ----------------------------------------------------------------------- */
1532
1533/* i2c implementation */
1534static struct i2c_driver i2c_driver_saa7115 = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001535 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +01001536 .name = "saa7115",
1537 },
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001538 .id = I2C_DRIVERID_SAA711X,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001539 .attach_adapter = saa7115_probe,
1540 .detach_client = saa7115_detach,
1541 .command = saa7115_command,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001542};
1543
1544
1545static int __init saa7115_init_module(void)
1546{
1547 return i2c_add_driver(&i2c_driver_saa7115);
1548}
1549
1550static void __exit saa7115_cleanup_module(void)
1551{
1552 i2c_del_driver(&i2c_driver_saa7115);
1553}
1554
1555module_init(saa7115_init_module);
1556module_exit(saa7115_cleanup_module);