blob: c0e66a88be4fab28f7118ab41a5270b8aed16fd8 [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 Verkuil9415f4b2008-11-29 12:55:19 -030047#include <media/v4l2-device.h>
Hans Verkuil3434eb72007-04-27 12:31:08 -030048#include <media/v4l2-chip-ident.h>
Hans Verkuilef6078e2009-03-29 17:32:35 -030049#include <media/v4l2-i2c-drv.h>
Hans Verkuil1f8f5fa2006-03-25 09:20:28 -030050#include <media/saa7115.h>
Hans Verkuil3578d3d2006-01-09 15:25:41 -020051#include <asm/div64.h>
Hans Verkuile19b2fc2005-11-13 16:08:04 -080052
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -030053#define VRES_60HZ (480+16)
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030054
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -030055MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -030056MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
57 "Hans Verkuil, Mauro Carvalho Chehab");
Hans Verkuile19b2fc2005-11-13 16:08:04 -080058MODULE_LICENSE("GPL");
59
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030060static int debug;
Hans Verkuilfac9e892006-01-09 15:32:40 -020061module_param(debug, bool, 0644);
Hans Verkuile19b2fc2005-11-13 16:08:04 -080062
63MODULE_PARM_DESC(debug, "Debug level (0-1)");
64
Hans Verkuile19b2fc2005-11-13 16:08:04 -080065
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -030066struct saa711x_state {
Hans Verkuil9415f4b2008-11-29 12:55:19 -030067 struct v4l2_subdev sd;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080068 v4l2_std_id std;
69 int input;
Marco Schluessler4cbca182007-01-21 19:43:38 -030070 int output;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080071 int enable;
Hans Verkuil3faeeae2006-01-09 15:25:44 -020072 int radio;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080073 int bright;
74 int contrast;
75 int hue;
76 int sat;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -030077 int width;
78 int height;
Hans Verkuil3434eb72007-04-27 12:31:08 -030079 u32 ident;
Hans Verkuil3578d3d2006-01-09 15:25:41 -020080 u32 audclk_freq;
Hans Verkuilb7f82922006-04-02 12:50:42 -030081 u32 crystal_freq;
82 u8 ucgc;
83 u8 cgcdiv;
84 u8 apll;
Hans Verkuile19b2fc2005-11-13 16:08:04 -080085};
86
Hans Verkuil9415f4b2008-11-29 12:55:19 -030087static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
88{
89 return container_of(sd, struct saa711x_state, sd);
90}
91
Hans Verkuile19b2fc2005-11-13 16:08:04 -080092/* ----------------------------------------------------------------------- */
93
Hans Verkuil9415f4b2008-11-29 12:55:19 -030094static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
Hans Verkuile19b2fc2005-11-13 16:08:04 -080095{
Hans Verkuil9415f4b2008-11-29 12:55:19 -030096 struct i2c_client *client = v4l2_get_subdevdata(sd);
97
Hans Verkuile19b2fc2005-11-13 16:08:04 -080098 return i2c_smbus_write_byte_data(client, reg, value);
99}
100
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300101/* Sanity routine to check if a register is present */
102static int saa711x_has_reg(const int id, const u8 reg)
103{
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300104 if (id == V4L2_IDENT_SAA7111)
105 return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
106 (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300107
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300108 /* common for saa7113/4/5/8 */
109 if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
110 reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
111 reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
112 reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300113 return 0;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300114
115 switch (id) {
116 case V4L2_IDENT_SAA7113:
117 return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
118 reg != 0x5d && reg < 0x63;
119 case V4L2_IDENT_SAA7114:
120 return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
121 (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
122 reg != 0x81 && reg < 0xf0;
123 case V4L2_IDENT_SAA7115:
124 return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
125 case V4L2_IDENT_SAA7118:
126 return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
127 (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
128 (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
129 }
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300130 return 1;
131}
132
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300133static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800134{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300135 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800136 unsigned char reg, data;
137
138 while (*regs != 0x00) {
139 reg = *(regs++);
140 data = *(regs++);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300141
142 /* According with datasheets, reserved regs should be
143 filled with 0 - seems better not to touch on they */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300144 if (saa711x_has_reg(state->ident, reg)) {
145 if (saa711x_write(sd, reg, data) < 0)
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300146 return -1;
Mauro Carvalho Chehabd87edf22006-09-01 09:37:11 -0300147 } else {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300148 v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300149 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800150 }
151 return 0;
152}
153
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300154static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800155{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300156 struct i2c_client *client = v4l2_get_subdevdata(sd);
157
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800158 return i2c_smbus_read_byte_data(client, reg);
159}
160
161/* ----------------------------------------------------------------------- */
162
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300163/* SAA7111 initialization table */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300164static const unsigned char saa7111_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300165 R_01_INC_DELAY, 0x00, /* reserved */
166
167 /*front end */
168 R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
169 R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
170 * GAFIX=0, GAI1=256, GAI2=256 */
171 R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
172 R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
173
174 /* decoder */
175 R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
176 * pixels after end of last line */
177 R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
178 * work with NTSC, too */
179 R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
180 * VTRC=1, HPLL=0, VNOI=0 */
181 R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
182 * VBLB=0, UPTCV=0, APER=1 */
183 R_0A_LUMA_BRIGHT_CNTL, 0x80,
184 R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
185 R_0C_CHROMA_SAT_CNTL, 0x40,
186 R_0D_CHROMA_HUE_CNTL, 0x00,
187 R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
188 * FCTC=0, CHBW=1 */
189 R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
190 R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
191 R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
192 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
193 R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
194 R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
195 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
196 R_15_VGATE_START_FID_CHG, 0x00,
197 R_16_VGATE_STOP, 0x00,
198 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
199
200 0x00, 0x00
201};
202
203/* SAA7113 init codes */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300204static const unsigned char saa7113_init[] = {
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300205 R_01_INC_DELAY, 0x08,
206 R_02_INPUT_CNTL_1, 0xc2,
207 R_03_INPUT_CNTL_2, 0x30,
208 R_04_INPUT_CNTL_3, 0x00,
209 R_05_INPUT_CNTL_4, 0x00,
210 R_06_H_SYNC_START, 0x89,
211 R_07_H_SYNC_STOP, 0x0d,
212 R_08_SYNC_CNTL, 0x88,
213 R_09_LUMA_CNTL, 0x01,
214 R_0A_LUMA_BRIGHT_CNTL, 0x80,
215 R_0B_LUMA_CONTRAST_CNTL, 0x47,
216 R_0C_CHROMA_SAT_CNTL, 0x40,
217 R_0D_CHROMA_HUE_CNTL, 0x00,
218 R_0E_CHROMA_CNTL_1, 0x01,
219 R_0F_CHROMA_GAIN_CNTL, 0x2a,
220 R_10_CHROMA_CNTL_2, 0x08,
221 R_11_MODE_DELAY_CNTL, 0x0c,
222 R_12_RT_SIGNAL_CNTL, 0x07,
223 R_13_RT_X_PORT_OUT_CNTL, 0x00,
224 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
225 R_15_VGATE_START_FID_CHG, 0x00,
226 R_16_VGATE_STOP, 0x00,
227 R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
228
229 0x00, 0x00
230};
231
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800232/* If a value differs from the Hauppauge driver values, then the comment starts with
233 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
234 Hauppauge driver sets. */
235
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300236/* SAA7114 and SAA7115 initialization table */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800237static const unsigned char saa7115_init_auto_input[] = {
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300238 /* Front-End Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300239 R_01_INC_DELAY, 0x48, /* white peak control disabled */
240 R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
241 R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
242 R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300243 /* Decoder Part */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300244 R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
245 R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -0300246 R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300247 R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
248 R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
249 R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
250 R_0D_CHROMA_HUE_CNTL, 0x00,
251 R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
252 R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
253 R_11_MODE_DELAY_CNTL, 0x00,
254 R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
255 R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
256 R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
257 R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
258 R_19_RAW_DATA_OFF_CNTL, 0x80,
259 R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
260 R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
261 R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
262 R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300263
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300264
265 R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
266
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300267 /* Power Device Control */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300268 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
269 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800270 0x00, 0x00
271};
272
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300273/* Used to reset saa7113, saa7114 and saa7115 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800274static const unsigned char saa7115_cfg_reset_scaler[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300275 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
276 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
277 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
278 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800279 0x00, 0x00
280};
281
282/* ============== SAA7715 VIDEO templates ============= */
283
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800284static const unsigned char saa7115_cfg_60hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300285 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
286 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800287
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300288 R_15_VGATE_START_FID_CHG, 0x03,
289 R_16_VGATE_STOP, 0x11,
290 R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800291
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300292 R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
293 R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800294
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300295 R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800296
297 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300298 R_90_A_TASK_HANDLING_CNTL, 0x80,
299 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
300 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
301 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
302
303 /* hoffset low (input), 0x0002 is minimum */
304 R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
305 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
306
307 /* hsize low (input), 0x02d0 = 720 */
308 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
309 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
310
311 R_98_A_VERT_INPUT_WINDOW_START, 0x05,
312 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
313
314 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
315 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
316
317 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
318 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
319
320 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
321 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800322
323 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300324 R_C0_B_TASK_HANDLING_CNTL, 0x00,
325 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
326 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
327 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800328
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300329 /* 0x0002 is minimum */
330 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
331 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800332
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300333 /* 0x02d0 = 720 */
334 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
335 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
336
337 /* vwindow start 0x12 = 18 */
338 R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
339 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
340
341 /* vwindow length 0xf8 = 248 */
Mauro Carvalho Chehab97d9e802006-09-03 09:38:11 -0300342 R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
343 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300344
345 /* hwindow 0x02d0 = 720 */
346 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
347 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
348
349 R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
350 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
351 R_F5_PULSGEN_LINE_LENGTH, 0xad,
352 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
353
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800354 0x00, 0x00
355};
356
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800357static const unsigned char saa7115_cfg_50hz_video[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300358 R_80_GLOBAL_CNTL_1, 0x00,
359 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800360
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300361 R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
362 R_16_VGATE_STOP, 0x16,
363 R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800364
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300365 R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
366 R_0E_CHROMA_CNTL_1, 0x07,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800367
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300368 R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800369
370 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300371 R_90_A_TASK_HANDLING_CNTL, 0x81,
372 R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
373 R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
374 R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
375
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800376 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
377 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300378 /* hoffset low (input), 0x0002 is minimum */
379 R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
380 R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
381
382 /* hsize low (input), 0x02d0 = 720 */
383 R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
384 R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
385
386 R_98_A_VERT_INPUT_WINDOW_START, 0x03,
387 R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
388
389 /* vsize 0x12 = 18 */
390 R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
391 R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
392
393 /* hsize 0x05a0 = 1440 */
394 R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
395 R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
396 R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
397 R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800398
399 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300400 R_C0_B_TASK_HANDLING_CNTL, 0x00,
401 R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
402 R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
403 R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800404
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300405 /* This is weird: the datasheet says that you should use 2 as the minimum value, */
406 /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
407 /* hoffset low (input), 0x0002 is minimum. See comment above. */
408 R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
409 R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800410
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300411 /* hsize 0x02d0 = 720 */
412 R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
413 R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
414
415 /* voffset 0x16 = 22 */
416 R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
417 R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
418
419 /* vsize 0x0120 = 288 */
420 R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
421 R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
422
423 /* hsize 0x02d0 = 720 */
424 R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
425 R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
426
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300427 R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
428 R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
429 R_F5_PULSGEN_LINE_LENGTH, 0xb0,
430 R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
431
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800432 0x00, 0x00
433};
434
435/* ============== SAA7715 VIDEO templates (end) ======= */
436
437static const unsigned char saa7115_cfg_vbi_on[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300438 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
439 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
440 R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
441 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
442 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
443
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800444 0x00, 0x00
445};
446
447static const unsigned char saa7115_cfg_vbi_off[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300448 R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
449 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
450 R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
451 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
452 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
453
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800454 0x00, 0x00
455};
456
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -0300457
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800458static const unsigned char saa7115_init_misc[] = {
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300459 R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300460 R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
461 R_84_I_PORT_SIGNAL_DEF, 0x20,
462 R_85_I_PORT_SIGNAL_POLAR, 0x21,
463 R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
464 R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800465
466 /* Task A */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300467 R_A0_A_HORIZ_PRESCALING, 0x01,
468 R_A1_A_ACCUMULATION_LENGTH, 0x00,
469 R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800470
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300471 /* Configure controls at nominal value*/
472 R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
473 R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
474 R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
475
476 /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
477 R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
478 R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
479
480 R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
481
482 /* must be horiz lum scaling / 2 */
483 R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
484 R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
485
486 /* must be offset luma / 2 */
487 R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
488
489 R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
490 R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
491
492 R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
493 R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
494
495 R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
496
497 R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
498 R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
499 R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
500 R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
501
502 R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
503 R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
504 R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
505 R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800506
507 /* Task B */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300508 R_D0_B_HORIZ_PRESCALING, 0x01,
509 R_D1_B_ACCUMULATION_LENGTH, 0x00,
510 R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800511
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300512 /* Configure controls at nominal value*/
513 R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
514 R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
515 R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800516
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300517 /* hor lum scaling 0x0400 = 1 */
518 R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
519 R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
520
521 R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
522
523 /* must be hor lum scaling / 2 */
524 R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
525 R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
526
527 /* must be offset luma / 2 */
528 R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
529
530 R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
531 R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
532
533 R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
534 R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
535
536 R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
537
538 R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
539 R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
540 R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
541 R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
542
543 R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
544 R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
545 R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
546 R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
547
548 R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
549 R_F3_PLL_INCREMENT, 0x46,
550 R_F4_PLL2_STATUS, 0x00,
551 R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
552 R_F8_PULSE_B_POS, 0x00,
553 R_F9_PULSE_B_POS_MSB, 0x4b,
554 R_FA_PULSE_C_POS, 0x00,
555 R_FB_PULSE_C_POS_MSB, 0x4b,
556
557 /* PLL2 lock detection settings: 71 lines 50% phase error */
558 R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800559
560 /* Turn off VBI */
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300561 R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
562 R_41_LCR_BASE, 0xff,
563 R_41_LCR_BASE+1, 0xff,
564 R_41_LCR_BASE+2, 0xff,
565 R_41_LCR_BASE+3, 0xff,
566 R_41_LCR_BASE+4, 0xff,
567 R_41_LCR_BASE+5, 0xff,
568 R_41_LCR_BASE+6, 0xff,
569 R_41_LCR_BASE+7, 0xff,
570 R_41_LCR_BASE+8, 0xff,
571 R_41_LCR_BASE+9, 0xff,
572 R_41_LCR_BASE+10, 0xff,
573 R_41_LCR_BASE+11, 0xff,
574 R_41_LCR_BASE+12, 0xff,
575 R_41_LCR_BASE+13, 0xff,
576 R_41_LCR_BASE+14, 0xff,
577 R_41_LCR_BASE+15, 0xff,
578 R_41_LCR_BASE+16, 0xff,
579 R_41_LCR_BASE+17, 0xff,
580 R_41_LCR_BASE+18, 0xff,
581 R_41_LCR_BASE+19, 0xff,
582 R_41_LCR_BASE+20, 0xff,
583 R_41_LCR_BASE+21, 0xff,
584 R_41_LCR_BASE+22, 0xff,
585 R_58_PROGRAM_FRAMING_CODE, 0x40,
586 R_59_H_OFF_FOR_SLICER, 0x47,
587 R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
588 R_5D_DID, 0xbd,
589 R_5E_SDID, 0x35,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800590
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300591 R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800592
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300593 R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
594 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
595 R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800596 0x00, 0x00
597};
598
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -0300599static int saa711x_odd_parity(u8 c)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800600{
601 c ^= (c >> 4);
602 c ^= (c >> 2);
603 c ^= (c >> 1);
604
605 return c & 1;
606}
607
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300608static int saa711x_decode_vps(u8 *dst, u8 *p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800609{
610 static const u8 biphase_tbl[] = {
611 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
612 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
613 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
614 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
615 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
616 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
617 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
618 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
619 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
620 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
621 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
622 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
623 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
624 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
625 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
626 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
627 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
628 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
629 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
630 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
631 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
632 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
633 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
634 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
635 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
636 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
637 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
638 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
639 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
640 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
641 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
642 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
643 };
644 int i;
645 u8 c, err = 0;
646
647 for (i = 0; i < 2 * 13; i += 2) {
648 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
649 c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
650 dst[i / 2] = c;
651 }
652 return err & 0xf0;
653}
654
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300655static int saa711x_decode_wss(u8 *p)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800656{
657 static const int wss_bits[8] = {
658 0, 0, 0, 1, 0, 1, 1, 1
659 };
660 unsigned char parity;
661 int wss = 0;
662 int i;
663
664 for (i = 0; i < 16; i++) {
665 int b1 = wss_bits[p[i] & 7];
666 int b2 = wss_bits[(p[i] >> 3) & 7];
667
668 if (b1 == b2)
669 return -1;
670 wss |= b2 << i;
671 }
672 parity = wss & 15;
673 parity ^= parity >> 2;
674 parity ^= parity >> 1;
675
676 if (!(parity & 1))
677 return -1;
678
679 return wss;
680}
681
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300682static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800683{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300684 struct saa711x_state *state = to_state(sd);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200685 u32 acpf;
686 u32 acni;
687 u32 hz;
688 u64 f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300689 u8 acc = 0; /* reg 0x3a, audio clock control */
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800690
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300691 /* Checks for chips that don't have audio clock (saa7111, saa7113) */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300692 if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300693 return 0;
694
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300695 v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200696
697 /* sanity check */
698 if (freq < 32000 || freq > 48000)
699 return -EINVAL;
700
701 /* hz is the refresh rate times 100 */
702 hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
703 /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
704 acpf = (25600 * freq) / hz;
705 /* acni = (256 * freq * 2^23) / crystal_frequency =
706 (freq * 2^(8+23)) / crystal_frequency =
Hans Verkuilb7f82922006-04-02 12:50:42 -0300707 (freq << 31) / crystal_frequency */
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200708 f = freq;
709 f = f << 31;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300710 do_div(f, state->crystal_freq);
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200711 acni = f;
Hans Verkuilb7f82922006-04-02 12:50:42 -0300712 if (state->ucgc) {
713 acpf = acpf * state->cgcdiv / 16;
714 acni = acni * state->cgcdiv / 16;
715 acc = 0x80;
716 if (state->cgcdiv == 3)
717 acc |= 0x40;
718 }
719 if (state->apll)
720 acc |= 0x08;
Hans Verkuil3578d3d2006-01-09 15:25:41 -0200721
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300722 saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
723 saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
724 saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300725
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300726 saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
727 saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300728 (acpf >> 8) & 0xff);
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300729 saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -0300730 (acpf >> 16) & 0x03);
731
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300732 saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
733 saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
734 saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800735 state->audclk_freq = freq;
736 return 0;
737}
738
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300739static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800740{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300741 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800742
743 switch (ctrl->id) {
744 case V4L2_CID_BRIGHTNESS:
745 if (ctrl->value < 0 || ctrl->value > 255) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300746 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800747 return -ERANGE;
748 }
749
750 state->bright = ctrl->value;
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300751 saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800752 break;
753
754 case V4L2_CID_CONTRAST:
755 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300756 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800757 return -ERANGE;
758 }
759
760 state->contrast = ctrl->value;
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300761 saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800762 break;
763
764 case V4L2_CID_SATURATION:
765 if (ctrl->value < 0 || ctrl->value > 127) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300766 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800767 return -ERANGE;
768 }
769
770 state->sat = ctrl->value;
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300771 saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800772 break;
773
774 case V4L2_CID_HUE:
Hans Verkuilde6476f52009-01-29 16:09:13 -0300775 if (ctrl->value < -128 || ctrl->value > 127) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300776 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800777 return -ERANGE;
778 }
779
780 state->hue = ctrl->value;
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300781 saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800782 break;
Hans Verkuil3faeeae2006-01-09 15:25:44 -0200783
784 default:
785 return -EINVAL;
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800786 }
787
788 return 0;
789}
790
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300791static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800792{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300793 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800794
795 switch (ctrl->id) {
796 case V4L2_CID_BRIGHTNESS:
797 ctrl->value = state->bright;
798 break;
799 case V4L2_CID_CONTRAST:
800 ctrl->value = state->contrast;
801 break;
802 case V4L2_CID_SATURATION:
803 ctrl->value = state->sat;
804 break;
805 case V4L2_CID_HUE:
806 ctrl->value = state->hue;
807 break;
808 default:
809 return -EINVAL;
810 }
811
812 return 0;
813}
814
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300815static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300816{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300817 struct saa711x_state *state = to_state(sd);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300818 int HPSC, HFSC;
819 int VSCY;
820 int res;
821 int is_50hz = state->std & V4L2_STD_625_50;
822 int Vsrc = is_50hz ? 576 : 480;
823
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300824 v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300825
826 /* FIXME need better bounds checking here */
827 if ((width < 1) || (width > 1440))
828 return -EINVAL;
829 if ((height < 1) || (height > Vsrc))
830 return -EINVAL;
831
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300832 if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300833 /* Decoder only supports 720 columns and 480 or 576 lines */
834 if (width != 720)
835 return -EINVAL;
836 if (height != Vsrc)
837 return -EINVAL;
838 }
839
840 state->width = width;
841 state->height = height;
842
843 if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
844 return 0;
845
846 /* probably have a valid size, let's set it */
847 /* Set output width/height */
848 /* width */
849
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300850 saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300851 (u8) (width & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300852 saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300853 (u8) ((width >> 8) & 0xff));
854
855 /* Vertical Scaling uses height/2 */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300856 res = height / 2;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300857
858 /* On 60Hz, it is using a higher Vertical Output Size */
859 if (!is_50hz)
Hans Verkuild0d30c02006-11-25 09:45:50 -0300860 res += (VRES_60HZ - 480) >> 1;
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300861
862 /* height */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300863 saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300864 (u8) (res & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300865 saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300866 (u8) ((res >> 8) & 0xff));
867
868 /* Scaling settings */
869 /* Hprescaler is floor(inres/outres) */
870 HPSC = (int)(720 / width);
871 /* 0 is not allowed (div. by zero) */
872 HPSC = HPSC ? HPSC : 1;
873 HFSC = (int)((1024 * 720) / (HPSC * width));
874 /* FIXME hardcodes to "Task B"
875 * write H prescaler integer */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300876 saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300877 (u8) (HPSC & 0x3f));
878
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300879 v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300880 /* write H fine-scaling (luminance) */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300881 saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300882 (u8) (HFSC & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300883 saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300884 (u8) ((HFSC >> 8) & 0xff));
885 /* write H fine-scaling (chrominance)
886 * must be lum/2, so i'll just bitshift :) */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300887 saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300888 (u8) ((HFSC >> 1) & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300889 saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300890 (u8) ((HFSC >> 9) & 0xff));
891
892 VSCY = (int)((1024 * Vsrc) / height);
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300893 v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300894
895 /* Correct Contrast and Luminance */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300896 saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300897 (u8) (64 * 1024 / VSCY));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300898 saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300899 (u8) (64 * 1024 / VSCY));
900
901 /* write V fine-scaling (luminance) */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300902 saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300903 (u8) (VSCY & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300904 saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300905 (u8) ((VSCY >> 8) & 0xff));
906 /* write V fine-scaling (chrominance) */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300907 saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300908 (u8) (VSCY & 0xff));
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300909 saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300910 (u8) ((VSCY >> 8) & 0xff));
911
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300912 saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300913
914 /* Activates task "B" */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300915 saa711x_write(sd, R_80_GLOBAL_CNTL_1,
916 saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300917
918 return 0;
919}
920
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300921static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800922{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300923 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800924
Hans Verkuil30b54d52006-01-09 15:25:43 -0200925 /* Prevent unnecessary standard changes. During a standard
926 change the I-Port is temporarily disabled. Any devices
927 reading from that port can get confused.
Hans Verkuilbccfa442009-03-30 06:55:27 -0300928 Note that s_std is also used to switch from
929 radio to TV mode, so if a s_std is broadcast to
Hans Verkuil30b54d52006-01-09 15:25:43 -0200930 all I2C devices then you do not want to have an unwanted
931 side-effect here. */
932 if (std == state->std)
933 return;
934
Mauro Carvalho Chehabd9dce962006-09-02 12:59:38 -0300935 state->std = std;
936
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800937 // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
938 if (std & V4L2_STD_525_60) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300939 v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
940 saa711x_writeregs(sd, saa7115_cfg_60hz_video);
941 saa711x_set_size(sd, 720, 480);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800942 } else {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300943 v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
944 saa711x_writeregs(sd, saa7115_cfg_50hz_video);
945 saa711x_set_size(sd, 720, 576);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800946 }
947
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300948 /* Register 0E - Bits D6-D4 on NO-AUTO mode
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300949 (SAA7111 and SAA7113 doesn't have auto mode)
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300950 50 Hz / 625 lines 60 Hz / 525 lines
951 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
952 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
953 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
954 011 NTSC N (3.58MHz) PAL M (3.58MHz)
955 100 reserved NTSC-Japan (3.58MHz)
956 */
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300957 if (state->ident == V4L2_IDENT_SAA7111 ||
958 state->ident == V4L2_IDENT_SAA7113) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300959 u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300960
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300961 if (std == V4L2_STD_PAL_M) {
Hans Verkuil01342352006-03-25 08:19:47 -0300962 reg |= 0x30;
Hans Verkuile0028022008-04-22 14:45:51 -0300963 } else if (std == V4L2_STD_PAL_Nc) {
Hans Verkuil01342352006-03-25 08:19:47 -0300964 reg |= 0x20;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300965 } else if (std == V4L2_STD_PAL_60) {
Hans Verkuil01342352006-03-25 08:19:47 -0300966 reg |= 0x10;
Mauro Carvalho Chehab02c17222006-03-16 18:44:07 -0300967 } else if (std == V4L2_STD_NTSC_M_JP) {
Hans Verkuil01342352006-03-25 08:19:47 -0300968 reg |= 0x40;
Mauro Carvalho Chehaba9aaec42007-03-13 13:41:49 -0300969 } else if (std & V4L2_STD_SECAM) {
Pádraig Bradyfc2fa312006-10-09 08:02:17 -0300970 reg |= 0x50;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300971 }
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300972 saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300973 } else {
974 /* restart task B if needed */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300975 int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
Mauro Carvalho Chehabf89982a2006-03-14 16:33:33 -0300976
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300977 if (taskb && state->ident == V4L2_IDENT_SAA7114) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300978 saa711x_writeregs(sd, saa7115_cfg_vbi_on);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300979 }
980
981 /* switch audio mode too! */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300982 saa711x_s_clock_freq(sd, state->audclk_freq);
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300983 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800984}
985
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800986/* setup the sliced VBI lcr registers according to the sliced VBI format */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300987static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800988{
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300989 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -0800990 int is_50hz = (state->std & V4L2_STD_625_50);
991 u8 lcr[24];
992 int i, x;
993
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300994#if 1
995 /* saa7113/7114/7118 VBI support are experimental */
Hans Verkuil9415f4b2008-11-29 12:55:19 -0300996 if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -0300997 return;
998
999#else
1000 /* SAA7113 and SAA7118 also should support VBI - Need testing */
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001001 if (state->ident != V4L2_IDENT_SAA7115)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001002 return;
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001003#endif
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001004
1005 for (i = 0; i <= 23; i++)
1006 lcr[i] = 0xff;
1007
Hans Verkuila8b86432008-10-04 08:05:30 -03001008 if (fmt == NULL) {
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001009 /* raw VBI */
1010 if (is_50hz)
1011 for (i = 6; i <= 23; i++)
1012 lcr[i] = 0xdd;
1013 else
1014 for (i = 10; i <= 21; i++)
1015 lcr[i] = 0xdd;
1016 } else {
1017 /* sliced VBI */
1018 /* first clear lines that cannot be captured */
1019 if (is_50hz) {
1020 for (i = 0; i <= 5; i++)
1021 fmt->service_lines[0][i] =
1022 fmt->service_lines[1][i] = 0;
1023 }
1024 else {
1025 for (i = 0; i <= 9; i++)
1026 fmt->service_lines[0][i] =
1027 fmt->service_lines[1][i] = 0;
1028 for (i = 22; i <= 23; i++)
1029 fmt->service_lines[0][i] =
1030 fmt->service_lines[1][i] = 0;
1031 }
1032
1033 /* Now set the lcr values according to the specified service */
1034 for (i = 6; i <= 23; i++) {
1035 lcr[i] = 0;
1036 for (x = 0; x <= 1; x++) {
1037 switch (fmt->service_lines[1-x][i]) {
1038 case 0:
1039 lcr[i] |= 0xf << (4 * x);
1040 break;
Hans Verkuil9bc74002006-03-29 18:02:51 -03001041 case V4L2_SLICED_TELETEXT_B:
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001042 lcr[i] |= 1 << (4 * x);
1043 break;
1044 case V4L2_SLICED_CAPTION_525:
1045 lcr[i] |= 4 << (4 * x);
1046 break;
1047 case V4L2_SLICED_WSS_625:
1048 lcr[i] |= 5 << (4 * x);
1049 break;
1050 case V4L2_SLICED_VPS:
1051 lcr[i] |= 7 << (4 * x);
1052 break;
1053 }
1054 }
1055 }
1056 }
1057
1058 /* write the lcr registers */
1059 for (i = 2; i <= 23; i++) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001060 saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001061 }
1062
1063 /* enable/disable raw VBI capturing */
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001064 saa711x_writeregs(sd, fmt == NULL ?
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001065 saa7115_cfg_vbi_on :
1066 saa7115_cfg_vbi_off);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001067}
1068
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001069static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001070{
1071 static u16 lcr2vbi[] = {
Hans Verkuil9bc74002006-03-29 18:02:51 -03001072 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001073 0, V4L2_SLICED_CAPTION_525, /* 4 */
1074 V4L2_SLICED_WSS_625, 0, /* 5 */
1075 V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
1076 0, 0, 0, 0
1077 };
1078 struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
1079 int i;
1080
1081 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
1082 return -EINVAL;
1083 memset(sliced, 0, sizeof(*sliced));
1084 /* done if using raw VBI */
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001085 if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001086 return 0;
1087 for (i = 2; i <= 23; i++) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001088 u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001089
1090 sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1091 sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1092 sliced->service_set |=
1093 sliced->service_lines[0][i] | sliced->service_lines[1][i];
1094 }
1095 return 0;
1096}
1097
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001098static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001099{
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001100 if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001101 saa711x_set_lcr(sd, &fmt->fmt.sliced);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001102 return 0;
1103 }
Hans Verkuila8b86432008-10-04 08:05:30 -03001104 if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001105 saa711x_set_lcr(sd, NULL);
Hans Verkuila8b86432008-10-04 08:05:30 -03001106 return 0;
1107 }
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001108 if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1109 return -EINVAL;
1110
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001111 return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001112}
1113
1114/* Decode the sliced VBI data stream as created by the saa7115.
1115 The format is described in the saa7115 datasheet in Tables 25 and 26
1116 and in Figure 33.
1117 The current implementation uses SAV/EAV codes and not the ancillary data
Mauro Carvalho Chehab96ecfc42006-08-28 19:18:49 -03001118 headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001119 code. */
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001120static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001121{
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001122 struct saa711x_state *state = to_state(sd);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001123 static const char vbi_no_data_pattern[] = {
1124 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1125 };
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001126 u8 *p = vbi->p;
1127 u32 wss;
1128 int id1, id2; /* the ID1 and ID2 bytes from the internal header */
1129
1130 vbi->type = 0; /* mark result as a failure */
1131 id1 = p[2];
1132 id2 = p[3];
1133 /* Note: the field bit is inverted for 60 Hz video */
1134 if (state->std & V4L2_STD_525_60)
1135 id1 ^= 0x40;
1136
1137 /* Skip internal header, p now points to the start of the payload */
1138 p += 4;
1139 vbi->p = p;
1140
1141 /* calculate field and line number of the VBI packet (1-23) */
1142 vbi->is_second_field = ((id1 & 0x40) != 0);
1143 vbi->line = (id1 & 0x3f) << 3;
1144 vbi->line |= (id2 & 0x70) >> 4;
1145
1146 /* Obtain data type */
1147 id2 &= 0xf;
1148
1149 /* If the VBI slicer does not detect any signal it will fill up
1150 the payload buffer with 0xa0 bytes. */
1151 if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001152 return 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001153
1154 /* decode payloads */
1155 switch (id2) {
1156 case 1:
Hans Verkuil9bc74002006-03-29 18:02:51 -03001157 vbi->type = V4L2_SLICED_TELETEXT_B;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001158 break;
1159 case 4:
Mauro Carvalho Chehab59ba9152006-08-30 05:34:36 -03001160 if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001161 return 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001162 vbi->type = V4L2_SLICED_CAPTION_525;
1163 break;
1164 case 5:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001165 wss = saa711x_decode_wss(p);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001166 if (wss == -1)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001167 return 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001168 p[0] = wss & 0xff;
1169 p[1] = wss >> 8;
1170 vbi->type = V4L2_SLICED_WSS_625;
1171 break;
1172 case 7:
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001173 if (saa711x_decode_vps(p, p) != 0)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001174 return 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001175 vbi->type = V4L2_SLICED_VPS;
1176 break;
1177 default:
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001178 break;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001179 }
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001180 return 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001181}
1182
1183/* ============ SAA7115 AUDIO settings (end) ============= */
1184
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001185static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001186{
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001187 struct saa711x_state *state = to_state(sd);
1188 int status;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001189
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001190 if (state->radio)
1191 return 0;
1192 status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001193
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001194 v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
1195 vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1196 return 0;
1197}
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001198
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001199static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
1200{
1201 switch (qc->id) {
1202 case V4L2_CID_BRIGHTNESS:
Hans Verkuil10afbef2009-02-21 18:47:24 -03001203 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001204 case V4L2_CID_CONTRAST:
1205 case V4L2_CID_SATURATION:
Hans Verkuil10afbef2009-02-21 18:47:24 -03001206 return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001207 case V4L2_CID_HUE:
Hans Verkuil10afbef2009-02-21 18:47:24 -03001208 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001209 default:
1210 return -EINVAL;
1211 }
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001212}
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001213
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001214static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1215{
1216 struct saa711x_state *state = to_state(sd);
1217
1218 state->radio = 0;
1219 saa711x_set_v4lstd(sd, std);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001220 return 0;
1221}
1222
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001223static int saa711x_s_radio(struct v4l2_subdev *sd)
1224{
1225 struct saa711x_state *state = to_state(sd);
1226
1227 state->radio = 1;
1228 return 0;
1229}
1230
1231static int saa711x_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
1232{
1233 struct saa711x_state *state = to_state(sd);
1234 u32 input = route->input;
1235 u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
1236
1237 v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n", route->input, route->output);
1238 /* saa7111/3 does not have these inputs */
1239 if ((state->ident == V4L2_IDENT_SAA7113 ||
1240 state->ident == V4L2_IDENT_SAA7111) &&
1241 (route->input == SAA7115_COMPOSITE4 ||
1242 route->input == SAA7115_COMPOSITE5)) {
1243 return -EINVAL;
1244 }
1245 if (route->input > SAA7115_SVIDEO3)
1246 return -EINVAL;
1247 if (route->output > SAA7115_IPORT_ON)
1248 return -EINVAL;
1249 if (state->input == route->input && state->output == route->output)
1250 return 0;
1251 v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
1252 (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
1253 (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
1254 state->input = route->input;
1255
1256 /* saa7111 has slightly different input numbering */
1257 if (state->ident == V4L2_IDENT_SAA7111) {
1258 if (input >= SAA7115_COMPOSITE4)
1259 input -= 2;
1260 /* saa7111 specific */
1261 saa711x_write(sd, R_10_CHROMA_CNTL_2,
1262 (saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
1263 ((route->output & 0xc0) ^ 0x40));
1264 saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
1265 (saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
1266 ((route->output & 2) ? 0x0a : 0));
1267 }
1268
1269 /* select mode */
1270 saa711x_write(sd, R_02_INPUT_CNTL_1,
1271 (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
1272 input);
1273
1274 /* bypass chrominance trap for S-Video modes */
1275 saa711x_write(sd, R_09_LUMA_CNTL,
1276 (saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
1277 (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1278
1279 state->output = route->output;
1280 if (state->ident == V4L2_IDENT_SAA7114 ||
1281 state->ident == V4L2_IDENT_SAA7115) {
1282 saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
1283 (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
1284 (state->output & 0x01));
1285 }
1286 return 0;
1287}
1288
1289static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
1290{
1291 struct saa711x_state *state = to_state(sd);
1292
1293 if (state->ident != V4L2_IDENT_SAA7111)
1294 return -EINVAL;
1295 saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
1296 (val ? 0x80 : 0));
1297 return 0;
1298}
1299
1300static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
1301{
1302 struct saa711x_state *state = to_state(sd);
1303
1304 v4l2_dbg(1, debug, sd, "%s output\n",
1305 enable ? "enable" : "disable");
1306
Hans Verkuil674a3232009-02-18 12:22:16 -03001307 if (state->enable == enable)
1308 return 0;
1309 state->enable = enable;
1310 if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED))
1311 return 0;
1312 saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable);
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001313 return 0;
1314}
1315
Hans Verkuil3ff4ad82009-04-01 03:15:52 -03001316static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001317{
1318 struct saa711x_state *state = to_state(sd);
1319
Hans Verkuil3ff4ad82009-04-01 03:15:52 -03001320 if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001321 return -EINVAL;
Hans Verkuil3ff4ad82009-04-01 03:15:52 -03001322 state->crystal_freq = freq;
1323 state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
1324 state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
1325 state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001326 saa711x_s_clock_freq(sd, state->audclk_freq);
1327 return 0;
1328}
1329
1330static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
1331{
1332 v4l2_dbg(1, debug, sd, "decoder RESET\n");
1333 saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
1334 return 0;
1335}
1336
1337static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
1338{
1339 /* Note: the internal field ID is inverted for NTSC,
1340 so data->field 0 maps to the saa7115 even field,
1341 whereas for PAL it maps to the saa7115 odd field. */
1342 switch (data->id) {
1343 case V4L2_SLICED_WSS_625:
1344 if (saa711x_read(sd, 0x6b) & 0xc0)
1345 return -EIO;
1346 data->data[0] = saa711x_read(sd, 0x6c);
1347 data->data[1] = saa711x_read(sd, 0x6d);
1348 return 0;
1349 case V4L2_SLICED_CAPTION_525:
1350 if (data->field == 0) {
1351 /* CC */
1352 if (saa711x_read(sd, 0x66) & 0x30)
1353 return -EIO;
1354 data->data[0] = saa711x_read(sd, 0x69);
1355 data->data[1] = saa711x_read(sd, 0x6a);
1356 return 0;
1357 }
1358 /* XDS */
1359 if (saa711x_read(sd, 0x66) & 0xc0)
1360 return -EIO;
1361 data->data[0] = saa711x_read(sd, 0x67);
1362 data->data[1] = saa711x_read(sd, 0x68);
1363 return 0;
1364 default:
1365 return -EINVAL;
1366 }
1367}
1368
Hans Verkuil17bdd9d2009-02-18 12:35:33 -03001369static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
1370{
1371 struct saa711x_state *state = to_state(sd);
1372 int reg1e;
1373
1374 *std = V4L2_STD_ALL;
1375 if (state->ident != V4L2_IDENT_SAA7115)
1376 return 0;
1377 reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1378
1379 switch (reg1e & 0x03) {
1380 case 1:
1381 *std = V4L2_STD_NTSC;
1382 break;
1383 case 2:
1384 *std = V4L2_STD_PAL;
1385 break;
1386 case 3:
1387 *std = V4L2_STD_SECAM;
1388 break;
1389 default:
1390 break;
1391 }
1392 return 0;
1393}
1394
1395static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
1396{
1397 struct saa711x_state *state = to_state(sd);
1398 int reg1e = 0x80;
1399 int reg1f;
1400
1401 *status = V4L2_IN_ST_NO_SIGNAL;
1402 if (state->ident == V4L2_IDENT_SAA7115)
1403 reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1404 reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1405 if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
1406 *status = 0;
1407 return 0;
1408}
1409
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001410#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001411static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001412{
1413 struct i2c_client *client = v4l2_get_subdevdata(sd);
1414
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001415 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001416 return -EINVAL;
1417 if (!capable(CAP_SYS_ADMIN))
1418 return -EPERM;
1419 reg->val = saa711x_read(sd, reg->reg & 0xff);
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001420 reg->size = 1;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001421 return 0;
1422}
1423
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001424static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001425{
1426 struct i2c_client *client = v4l2_get_subdevdata(sd);
1427
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001428 if (!v4l2_chip_match_i2c_client(client, &reg->match))
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001429 return -EINVAL;
1430 if (!capable(CAP_SYS_ADMIN))
1431 return -EPERM;
1432 saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
1433 return 0;
1434}
1435#endif
1436
Hans Verkuilaecde8b52008-12-30 07:14:19 -03001437static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001438{
1439 struct saa711x_state *state = to_state(sd);
1440 struct i2c_client *client = v4l2_get_subdevdata(sd);
1441
1442 return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
1443}
1444
1445static int saa711x_log_status(struct v4l2_subdev *sd)
1446{
1447 struct saa711x_state *state = to_state(sd);
1448 int reg1e, reg1f;
1449 int signalOk;
1450 int vcr;
1451
1452 v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
1453 if (state->ident != V4L2_IDENT_SAA7115) {
1454 /* status for the saa7114 */
1455 reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1456 signalOk = (reg1f & 0xc1) == 0x81;
1457 v4l2_info(sd, "Video signal: %s\n", signalOk ? "ok" : "bad");
1458 v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
1459 return 0;
1460 }
1461
1462 /* status for the saa7115 */
1463 reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1464 reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1465
1466 signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1467 vcr = !(reg1f & 0x10);
1468
1469 if (state->input >= 6)
1470 v4l2_info(sd, "Input: S-Video %d\n", state->input - 6);
1471 else
1472 v4l2_info(sd, "Input: Composite %d\n", state->input);
1473 v4l2_info(sd, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1474 v4l2_info(sd, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
1475
1476 switch (reg1e & 0x03) {
1477 case 1:
1478 v4l2_info(sd, "Detected format: NTSC\n");
1479 break;
1480 case 2:
1481 v4l2_info(sd, "Detected format: PAL\n");
1482 break;
1483 case 3:
1484 v4l2_info(sd, "Detected format: SECAM\n");
1485 break;
1486 default:
1487 v4l2_info(sd, "Detected format: BW/No color\n");
1488 break;
1489 }
1490 v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height);
1491 return 0;
1492}
1493
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001494/* ----------------------------------------------------------------------- */
1495
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001496static const struct v4l2_subdev_core_ops saa711x_core_ops = {
1497 .log_status = saa711x_log_status,
1498 .g_chip_ident = saa711x_g_chip_ident,
1499 .g_ctrl = saa711x_g_ctrl,
1500 .s_ctrl = saa711x_s_ctrl,
1501 .queryctrl = saa711x_queryctrl,
Hans Verkuilf41737e2009-04-01 03:52:39 -03001502 .s_std = saa711x_s_std,
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001503 .reset = saa711x_reset,
1504 .s_gpio = saa711x_s_gpio,
1505#ifdef CONFIG_VIDEO_ADV_DEBUG
1506 .g_register = saa711x_g_register,
1507 .s_register = saa711x_s_register,
1508#endif
1509};
1510
1511static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001512 .s_radio = saa711x_s_radio,
1513 .g_tuner = saa711x_g_tuner,
1514};
1515
1516static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
1517 .s_clock_freq = saa711x_s_clock_freq,
1518};
1519
1520static const struct v4l2_subdev_video_ops saa711x_video_ops = {
1521 .s_routing = saa711x_s_routing,
1522 .s_crystal_freq = saa711x_s_crystal_freq,
1523 .g_fmt = saa711x_g_fmt,
1524 .s_fmt = saa711x_s_fmt,
1525 .g_vbi_data = saa711x_g_vbi_data,
1526 .decode_vbi_line = saa711x_decode_vbi_line,
1527 .s_stream = saa711x_s_stream,
Hans Verkuil17bdd9d2009-02-18 12:35:33 -03001528 .querystd = saa711x_querystd,
1529 .g_input_status = saa711x_g_input_status,
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001530};
1531
1532static const struct v4l2_subdev_ops saa711x_ops = {
1533 .core = &saa711x_core_ops,
1534 .tuner = &saa711x_tuner_ops,
1535 .audio = &saa711x_audio_ops,
1536 .video = &saa711x_video_ops,
1537};
1538
1539/* ----------------------------------------------------------------------- */
1540
1541static int saa711x_probe(struct i2c_client *client,
Jean Delvared2653e92008-04-29 23:11:39 +02001542 const struct i2c_device_id *id)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001543{
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001544 struct saa711x_state *state;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001545 struct v4l2_subdev *sd;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001546 int i;
1547 char name[17];
Jean Delvareaf294862008-05-18 20:49:40 +02001548 char chip_id;
1549 int autodetect = !id || id->driver_data == 1;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001550
1551 /* Check if the adapter supports the needed features */
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001552 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Hans Verkuil188f3452007-09-16 10:47:15 -03001553 return -EIO;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001554
Hans Verkuild0d30c02006-11-25 09:45:50 -03001555 for (i = 0; i < 0x0f; i++) {
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001556 i2c_smbus_write_byte_data(client, 0, i);
1557 name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
Hans Verkuild0d30c02006-11-25 09:45:50 -03001558 if (name[i] > '9')
1559 name[i] += 'a' - '9' - 1;
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001560 }
Hans Verkuild0d30c02006-11-25 09:45:50 -03001561 name[i] = '\0';
Mauro Carvalho Chehab236f16d2006-08-28 08:25:29 -03001562
Jean Delvareaf294862008-05-18 20:49:40 +02001563 chip_id = name[5];
Mauro Carvalho Chehab3e7d3e52006-09-01 18:39:05 -03001564
Hans Verkuilf7668162006-11-25 09:40:28 -03001565 /* Check whether this chip is part of the saa711x series */
1566 if (memcmp(name, "1f711", 5)) {
1567 v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001568 client->addr << 1, name);
Hans Verkuil188f3452007-09-16 10:47:15 -03001569 return -ENODEV;
Hans Verkuilf7668162006-11-25 09:40:28 -03001570 }
1571
Jean Delvareaf294862008-05-18 20:49:40 +02001572 /* Safety check */
1573 if (!autodetect && id->name[6] != chip_id) {
1574 v4l_warn(client, "found saa711%c while %s was expected\n",
1575 chip_id, id->name);
1576 }
1577 snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
1578 v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
1579 client->addr << 1, client->adapter->name);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001580
Mauro Carvalho Chehab66ec11932006-08-29 22:52:32 -03001581 state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
Hans Verkuilc5bf2042008-09-03 17:12:09 -03001582 if (state == NULL)
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001583 return -ENOMEM;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001584 sd = &state->sd;
1585 v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001586 state->input = -1;
Marco Schluessler4cbca182007-01-21 19:43:38 -03001587 state->output = SAA7115_IPORT_ON;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001588 state->enable = 1;
Hans Verkuil3faeeae2006-01-09 15:25:44 -02001589 state->radio = 0;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001590 state->bright = 128;
1591 state->contrast = 64;
1592 state->hue = 0;
1593 state->sat = 64;
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001594 switch (chip_id) {
Jean Delvareaf294862008-05-18 20:49:40 +02001595 case '1':
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001596 state->ident = V4L2_IDENT_SAA7111;
1597 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001598 case '3':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001599 state->ident = V4L2_IDENT_SAA7113;
1600 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001601 case '4':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001602 state->ident = V4L2_IDENT_SAA7114;
1603 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001604 case '5':
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001605 state->ident = V4L2_IDENT_SAA7115;
1606 break;
Jean Delvareaf294862008-05-18 20:49:40 +02001607 case '8':
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001608 state->ident = V4L2_IDENT_SAA7118;
1609 break;
1610 default:
1611 state->ident = V4L2_IDENT_SAA7111;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001612 v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
Mauro Carvalho Chehab89f75ff2006-08-29 22:07:03 -03001613
Mauro Carvalho Chehabf5762e42006-03-13 13:31:31 -03001614 }
1615
Hans Verkuil3578d3d2006-01-09 15:25:41 -02001616 state->audclk_freq = 48000;
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001617
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001618 v4l2_dbg(1, debug, sd, "writing init values\n");
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001619
1620 /* init to 60hz/48khz */
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001621 state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
1622 switch (state->ident) {
1623 case V4L2_IDENT_SAA7111:
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001624 saa711x_writeregs(sd, saa7111_init);
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001625 break;
1626 case V4L2_IDENT_SAA7113:
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001627 saa711x_writeregs(sd, saa7113_init);
Mauro Carvalho Chehab183d8962006-09-12 20:02:09 -03001628 break;
1629 default:
Hans Verkuilb7f82922006-04-02 12:50:42 -03001630 state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001631 saa711x_writeregs(sd, saa7115_init_auto_input);
Hans Verkuilb7f82922006-04-02 12:50:42 -03001632 }
Hans Verkuil6bd6dff2008-09-06 15:26:44 -03001633 if (state->ident != V4L2_IDENT_SAA7111)
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001634 saa711x_writeregs(sd, saa7115_init_misc);
1635 saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001636
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001637 v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
1638 saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
1639 saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001640 return 0;
1641}
1642
1643/* ----------------------------------------------------------------------- */
1644
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001645static int saa711x_remove(struct i2c_client *client)
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001646{
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001647 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1648
1649 v4l2_device_unregister_subdev(sd);
1650 kfree(to_state(sd));
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001651 return 0;
1652}
1653
Jean Delvareaf294862008-05-18 20:49:40 +02001654static const struct i2c_device_id saa7115_id[] = {
Hans Verkuil9edd350f2008-07-17 13:22:51 -03001655 { "saa7115_auto", 1 }, /* autodetect */
Jean Delvareaf294862008-05-18 20:49:40 +02001656 { "saa7111", 0 },
1657 { "saa7113", 0 },
1658 { "saa7114", 0 },
1659 { "saa7115", 0 },
1660 { "saa7118", 0 },
1661 { }
1662};
1663MODULE_DEVICE_TABLE(i2c, saa7115_id);
1664
Hans Verkuilfbaa3d0d2007-09-13 11:19:39 -03001665static struct v4l2_i2c_driver_data v4l2_i2c_data = {
1666 .name = "saa7115",
Hans Verkuil9415f4b2008-11-29 12:55:19 -03001667 .probe = saa711x_probe,
1668 .remove = saa711x_remove,
Jean Delvareaf294862008-05-18 20:49:40 +02001669 .id_table = saa7115_id,
Hans Verkuile19b2fc2005-11-13 16:08:04 -08001670};