xref: /openbmc/linux/drivers/media/i2c/saa7115.c (revision 39c1cb2b)
1cb7a01acSMauro Carvalho Chehab /* saa711x - Philips SAA711x video decoder driver
2cb7a01acSMauro Carvalho Chehab  * This driver can work with saa7111, saa7111a, saa7113, saa7114,
3cb7a01acSMauro Carvalho Chehab  *			     saa7115 and saa7118.
4cb7a01acSMauro Carvalho Chehab  *
5cb7a01acSMauro Carvalho Chehab  * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
6cb7a01acSMauro Carvalho Chehab  * the saa7111 driver by Dave Perks.
7cb7a01acSMauro Carvalho Chehab  *
8cb7a01acSMauro Carvalho Chehab  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
9cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
10cb7a01acSMauro Carvalho Chehab  *
11cb7a01acSMauro Carvalho Chehab  * Slight changes for video timing and attachment output by
12cb7a01acSMauro Carvalho Chehab  * Wolfgang Scherr <scherr@net4you.net>
13cb7a01acSMauro Carvalho Chehab  *
14cb7a01acSMauro Carvalho Chehab  * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
15cb7a01acSMauro Carvalho Chehab  * by Ronald Bultje <rbultje@ronald.bitfreak.net>
16cb7a01acSMauro Carvalho Chehab  *
17cb7a01acSMauro Carvalho Chehab  * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
18cb7a01acSMauro Carvalho Chehab  * (2/17/2003)
19cb7a01acSMauro Carvalho Chehab  *
20cb7a01acSMauro Carvalho Chehab  * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
21cb7a01acSMauro Carvalho Chehab  *
22cb7a01acSMauro Carvalho Chehab  * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
23cb7a01acSMauro Carvalho Chehab  *	SAA7111, SAA7113 and SAA7118 support
24cb7a01acSMauro Carvalho Chehab  *
25cb7a01acSMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or
26cb7a01acSMauro Carvalho Chehab  * modify it under the terms of the GNU General Public License
27cb7a01acSMauro Carvalho Chehab  * as published by the Free Software Foundation; either version 2
28cb7a01acSMauro Carvalho Chehab  * of the License, or (at your option) any later version.
29cb7a01acSMauro Carvalho Chehab  *
30cb7a01acSMauro Carvalho Chehab  * This program is distributed in the hope that it will be useful,
31cb7a01acSMauro Carvalho Chehab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32cb7a01acSMauro Carvalho Chehab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33cb7a01acSMauro Carvalho Chehab  * GNU General Public License for more details.
34cb7a01acSMauro Carvalho Chehab  *
35cb7a01acSMauro Carvalho Chehab  * You should have received a copy of the GNU General Public License
36cb7a01acSMauro Carvalho Chehab  * along with this program; if not, write to the Free Software
37cb7a01acSMauro Carvalho Chehab  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
38cb7a01acSMauro Carvalho Chehab  */
39cb7a01acSMauro Carvalho Chehab 
40cb7a01acSMauro Carvalho Chehab #include "saa711x_regs.h"
41cb7a01acSMauro Carvalho Chehab 
42cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h>
43cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
44cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
45cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
46cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
47cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
48cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
49cb7a01acSMauro Carvalho Chehab #include <media/saa7115.h>
50cb7a01acSMauro Carvalho Chehab #include <asm/div64.h>
51cb7a01acSMauro Carvalho Chehab 
52cb7a01acSMauro Carvalho Chehab #define VRES_60HZ	(480+16)
53cb7a01acSMauro Carvalho Chehab 
54cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
55cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
56cb7a01acSMauro Carvalho Chehab 		"Hans Verkuil, Mauro Carvalho Chehab");
57cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
58cb7a01acSMauro Carvalho Chehab 
59cb7a01acSMauro Carvalho Chehab static bool debug;
60cb7a01acSMauro Carvalho Chehab module_param(debug, bool, 0644);
61cb7a01acSMauro Carvalho Chehab 
62cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)");
63cb7a01acSMauro Carvalho Chehab 
64cb7a01acSMauro Carvalho Chehab 
65e1277110SHans Verkuil enum saa711x_model {
66e1277110SHans Verkuil 	SAA7111A,
67e1277110SHans Verkuil 	SAA7111,
68e1277110SHans Verkuil 	SAA7113,
69e1277110SHans Verkuil 	GM7113C,
70e1277110SHans Verkuil 	SAA7114,
71e1277110SHans Verkuil 	SAA7115,
72e1277110SHans Verkuil 	SAA7118,
73e1277110SHans Verkuil };
74e1277110SHans Verkuil 
75cb7a01acSMauro Carvalho Chehab struct saa711x_state {
76cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
77cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler hdl;
78cb7a01acSMauro Carvalho Chehab 
79cb7a01acSMauro Carvalho Chehab 	struct {
80cb7a01acSMauro Carvalho Chehab 		/* chroma gain control cluster */
81cb7a01acSMauro Carvalho Chehab 		struct v4l2_ctrl *agc;
82cb7a01acSMauro Carvalho Chehab 		struct v4l2_ctrl *gain;
83cb7a01acSMauro Carvalho Chehab 	};
84cb7a01acSMauro Carvalho Chehab 
85cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std;
86cb7a01acSMauro Carvalho Chehab 	int input;
87cb7a01acSMauro Carvalho Chehab 	int output;
88cb7a01acSMauro Carvalho Chehab 	int enable;
89cb7a01acSMauro Carvalho Chehab 	int radio;
90cb7a01acSMauro Carvalho Chehab 	int width;
91cb7a01acSMauro Carvalho Chehab 	int height;
92e1277110SHans Verkuil 	enum saa711x_model ident;
93cb7a01acSMauro Carvalho Chehab 	u32 audclk_freq;
94cb7a01acSMauro Carvalho Chehab 	u32 crystal_freq;
951589037fSHans Verkuil 	bool ucgc;
96cb7a01acSMauro Carvalho Chehab 	u8 cgcdiv;
971589037fSHans Verkuil 	bool apll;
981589037fSHans Verkuil 	bool double_asclk;
99cb7a01acSMauro Carvalho Chehab };
100cb7a01acSMauro Carvalho Chehab 
101cb7a01acSMauro Carvalho Chehab static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
102cb7a01acSMauro Carvalho Chehab {
103cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct saa711x_state, sd);
104cb7a01acSMauro Carvalho Chehab }
105cb7a01acSMauro Carvalho Chehab 
106cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
107cb7a01acSMauro Carvalho Chehab {
108cb7a01acSMauro Carvalho Chehab 	return &container_of(ctrl->handler, struct saa711x_state, hdl)->sd;
109cb7a01acSMauro Carvalho Chehab }
110cb7a01acSMauro Carvalho Chehab 
111cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
112cb7a01acSMauro Carvalho Chehab 
113cb7a01acSMauro Carvalho Chehab static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
114cb7a01acSMauro Carvalho Chehab {
115cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
116cb7a01acSMauro Carvalho Chehab 
117cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_write_byte_data(client, reg, value);
118cb7a01acSMauro Carvalho Chehab }
119cb7a01acSMauro Carvalho Chehab 
120cb7a01acSMauro Carvalho Chehab /* Sanity routine to check if a register is present */
121cb7a01acSMauro Carvalho Chehab static int saa711x_has_reg(const int id, const u8 reg)
122cb7a01acSMauro Carvalho Chehab {
123e1277110SHans Verkuil 	if (id == SAA7111)
124cb7a01acSMauro Carvalho Chehab 		return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
125cb7a01acSMauro Carvalho Chehab 		       (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
126e1277110SHans Verkuil 	if (id == SAA7111A)
127cb7a01acSMauro Carvalho Chehab 		return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
128cb7a01acSMauro Carvalho Chehab 		       reg != 0x14 && reg != 0x18 && reg != 0x19 &&
129cb7a01acSMauro Carvalho Chehab 		       reg != 0x1d && reg != 0x1e;
130cb7a01acSMauro Carvalho Chehab 
131cb7a01acSMauro Carvalho Chehab 	/* common for saa7113/4/5/8 */
132cb7a01acSMauro Carvalho Chehab 	if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
133cb7a01acSMauro Carvalho Chehab 	    reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
134cb7a01acSMauro Carvalho Chehab 	    reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
135cb7a01acSMauro Carvalho Chehab 	    reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
136cb7a01acSMauro Carvalho Chehab 		return 0;
137cb7a01acSMauro Carvalho Chehab 
138cb7a01acSMauro Carvalho Chehab 	switch (id) {
139e1277110SHans Verkuil 	case GM7113C:
140241d89fcSJon Arne Jørgensen 		return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && reg < 0x20;
141e1277110SHans Verkuil 	case SAA7113:
142cb7a01acSMauro Carvalho Chehab 		return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
143cb7a01acSMauro Carvalho Chehab 		       reg != 0x5d && reg < 0x63;
144e1277110SHans Verkuil 	case SAA7114:
145cb7a01acSMauro Carvalho Chehab 		return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
146cb7a01acSMauro Carvalho Chehab 		       (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
147cb7a01acSMauro Carvalho Chehab 		       reg != 0x81 && reg < 0xf0;
148e1277110SHans Verkuil 	case SAA7115:
149cb7a01acSMauro Carvalho Chehab 		return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
150e1277110SHans Verkuil 	case SAA7118:
151cb7a01acSMauro Carvalho Chehab 		return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
152cb7a01acSMauro Carvalho Chehab 		       (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
153cb7a01acSMauro Carvalho Chehab 		       (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
154cb7a01acSMauro Carvalho Chehab 	}
155cb7a01acSMauro Carvalho Chehab 	return 1;
156cb7a01acSMauro Carvalho Chehab }
157cb7a01acSMauro Carvalho Chehab 
158cb7a01acSMauro Carvalho Chehab static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
159cb7a01acSMauro Carvalho Chehab {
160cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
161cb7a01acSMauro Carvalho Chehab 	unsigned char reg, data;
162cb7a01acSMauro Carvalho Chehab 
163cb7a01acSMauro Carvalho Chehab 	while (*regs != 0x00) {
164cb7a01acSMauro Carvalho Chehab 		reg = *(regs++);
165cb7a01acSMauro Carvalho Chehab 		data = *(regs++);
166cb7a01acSMauro Carvalho Chehab 
167cb7a01acSMauro Carvalho Chehab 		/* According with datasheets, reserved regs should be
168cb7a01acSMauro Carvalho Chehab 		   filled with 0 - seems better not to touch on they */
169cb7a01acSMauro Carvalho Chehab 		if (saa711x_has_reg(state->ident, reg)) {
170cb7a01acSMauro Carvalho Chehab 			if (saa711x_write(sd, reg, data) < 0)
171cb7a01acSMauro Carvalho Chehab 				return -1;
172cb7a01acSMauro Carvalho Chehab 		} else {
173cb7a01acSMauro Carvalho Chehab 			v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
174cb7a01acSMauro Carvalho Chehab 		}
175cb7a01acSMauro Carvalho Chehab 	}
176cb7a01acSMauro Carvalho Chehab 	return 0;
177cb7a01acSMauro Carvalho Chehab }
178cb7a01acSMauro Carvalho Chehab 
179cb7a01acSMauro Carvalho Chehab static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
180cb7a01acSMauro Carvalho Chehab {
181cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
182cb7a01acSMauro Carvalho Chehab 
183cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_read_byte_data(client, reg);
184cb7a01acSMauro Carvalho Chehab }
185cb7a01acSMauro Carvalho Chehab 
186cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
187cb7a01acSMauro Carvalho Chehab 
188cb7a01acSMauro Carvalho Chehab /* SAA7111 initialization table */
189cb7a01acSMauro Carvalho Chehab static const unsigned char saa7111_init[] = {
190cb7a01acSMauro Carvalho Chehab 	R_01_INC_DELAY, 0x00,		/* reserved */
191cb7a01acSMauro Carvalho Chehab 
192cb7a01acSMauro Carvalho Chehab 	/*front end */
193cb7a01acSMauro Carvalho Chehab 	R_02_INPUT_CNTL_1, 0xd0,	/* FUSE=3, GUDL=2, MODE=0 */
194cb7a01acSMauro Carvalho Chehab 	R_03_INPUT_CNTL_2, 0x23,	/* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
195cb7a01acSMauro Carvalho Chehab 					 * GAFIX=0, GAI1=256, GAI2=256 */
196cb7a01acSMauro Carvalho Chehab 	R_04_INPUT_CNTL_3, 0x00,	/* GAI1=256 */
197cb7a01acSMauro Carvalho Chehab 	R_05_INPUT_CNTL_4, 0x00,	/* GAI2=256 */
198cb7a01acSMauro Carvalho Chehab 
199cb7a01acSMauro Carvalho Chehab 	/* decoder */
200cb7a01acSMauro Carvalho Chehab 	R_06_H_SYNC_START, 0xf3,	/* HSB at  13(50Hz) /  17(60Hz)
201cb7a01acSMauro Carvalho Chehab 					 * pixels after end of last line */
202cb7a01acSMauro Carvalho Chehab 	R_07_H_SYNC_STOP, 0xe8,		/* HSS seems to be needed to
203cb7a01acSMauro Carvalho Chehab 					 * work with NTSC, too */
204cb7a01acSMauro Carvalho Chehab 	R_08_SYNC_CNTL, 0xc8,		/* AUFD=1, FSEL=1, EXFIL=0,
205cb7a01acSMauro Carvalho Chehab 					 * VTRC=1, HPLL=0, VNOI=0 */
206cb7a01acSMauro Carvalho Chehab 	R_09_LUMA_CNTL, 0x01,		/* BYPS=0, PREF=0, BPSS=0,
207cb7a01acSMauro Carvalho Chehab 					 * VBLB=0, UPTCV=0, APER=1 */
208cb7a01acSMauro Carvalho Chehab 	R_0A_LUMA_BRIGHT_CNTL, 0x80,
209cb7a01acSMauro Carvalho Chehab 	R_0B_LUMA_CONTRAST_CNTL, 0x47,	/* 0b - CONT=1.109 */
210cb7a01acSMauro Carvalho Chehab 	R_0C_CHROMA_SAT_CNTL, 0x40,
211cb7a01acSMauro Carvalho Chehab 	R_0D_CHROMA_HUE_CNTL, 0x00,
212cb7a01acSMauro Carvalho Chehab 	R_0E_CHROMA_CNTL_1, 0x01,	/* 0e - CDTO=0, CSTD=0, DCCF=0,
213cb7a01acSMauro Carvalho Chehab 					 * FCTC=0, CHBW=1 */
214cb7a01acSMauro Carvalho Chehab 	R_0F_CHROMA_GAIN_CNTL, 0x00,	/* reserved */
215cb7a01acSMauro Carvalho Chehab 	R_10_CHROMA_CNTL_2, 0x48,	/* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
216cb7a01acSMauro Carvalho Chehab 	R_11_MODE_DELAY_CNTL, 0x1c,	/* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
217cb7a01acSMauro Carvalho Chehab 					 * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
218cb7a01acSMauro Carvalho Chehab 	R_12_RT_SIGNAL_CNTL, 0x00,	/* 12 - output control 2 */
219cb7a01acSMauro Carvalho Chehab 	R_13_RT_X_PORT_OUT_CNTL, 0x00,	/* 13 - output control 3 */
220cb7a01acSMauro Carvalho Chehab 	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
221cb7a01acSMauro Carvalho Chehab 	R_15_VGATE_START_FID_CHG, 0x00,
222cb7a01acSMauro Carvalho Chehab 	R_16_VGATE_STOP, 0x00,
223cb7a01acSMauro Carvalho Chehab 	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
224cb7a01acSMauro Carvalho Chehab 
225cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
226cb7a01acSMauro Carvalho Chehab };
227cb7a01acSMauro Carvalho Chehab 
22804074f1fSMauro Carvalho Chehab /*
22904074f1fSMauro Carvalho Chehab  * This table has one illegal value, and some values that are not
23004074f1fSMauro Carvalho Chehab  * correct according to the datasheet initialization table.
23104074f1fSMauro Carvalho Chehab  *
23204074f1fSMauro Carvalho Chehab  *  If you need a table with legal/default values tell the driver in
23304074f1fSMauro Carvalho Chehab  *  i2c_board_info.platform_data, and you will get the gm7113c_init
23404074f1fSMauro Carvalho Chehab  *  table instead.
23504074f1fSMauro Carvalho Chehab  */
2362ccf12afSJon Arne Jørgensen 
2372ccf12afSJon Arne Jørgensen /* SAA7113 Init codes */
238cb7a01acSMauro Carvalho Chehab static const unsigned char saa7113_init[] = {
239cb7a01acSMauro Carvalho Chehab 	R_01_INC_DELAY, 0x08,
240cb7a01acSMauro Carvalho Chehab 	R_02_INPUT_CNTL_1, 0xc2,
241cb7a01acSMauro Carvalho Chehab 	R_03_INPUT_CNTL_2, 0x30,
242cb7a01acSMauro Carvalho Chehab 	R_04_INPUT_CNTL_3, 0x00,
243cb7a01acSMauro Carvalho Chehab 	R_05_INPUT_CNTL_4, 0x00,
2442ccf12afSJon Arne Jørgensen 	R_06_H_SYNC_START, 0x89,	/* Illegal value -119,
2452ccf12afSJon Arne Jørgensen 					 * min. value = -108 (0x94) */
246cb7a01acSMauro Carvalho Chehab 	R_07_H_SYNC_STOP, 0x0d,
2472ccf12afSJon Arne Jørgensen 	R_08_SYNC_CNTL, 0x88,		/* Not datasheet default.
2482ccf12afSJon Arne Jørgensen 					 * HTC = VTR mode, should be 0x98 */
249cb7a01acSMauro Carvalho Chehab 	R_09_LUMA_CNTL, 0x01,
250cb7a01acSMauro Carvalho Chehab 	R_0A_LUMA_BRIGHT_CNTL, 0x80,
251cb7a01acSMauro Carvalho Chehab 	R_0B_LUMA_CONTRAST_CNTL, 0x47,
252cb7a01acSMauro Carvalho Chehab 	R_0C_CHROMA_SAT_CNTL, 0x40,
253cb7a01acSMauro Carvalho Chehab 	R_0D_CHROMA_HUE_CNTL, 0x00,
254cb7a01acSMauro Carvalho Chehab 	R_0E_CHROMA_CNTL_1, 0x01,
255cb7a01acSMauro Carvalho Chehab 	R_0F_CHROMA_GAIN_CNTL, 0x2a,
2562ccf12afSJon Arne Jørgensen 	R_10_CHROMA_CNTL_2, 0x08,	/* Not datsheet default.
2572ccf12afSJon Arne Jørgensen 					 * VRLN enabled, should be 0x00 */
258cb7a01acSMauro Carvalho Chehab 	R_11_MODE_DELAY_CNTL, 0x0c,
2592ccf12afSJon Arne Jørgensen 	R_12_RT_SIGNAL_CNTL, 0x07,	/* Not datasheet default,
2602ccf12afSJon Arne Jørgensen 					 * should be 0x01 */
2612ccf12afSJon Arne Jørgensen 	R_13_RT_X_PORT_OUT_CNTL, 0x00,
2622ccf12afSJon Arne Jørgensen 	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
2632ccf12afSJon Arne Jørgensen 	R_15_VGATE_START_FID_CHG, 0x00,
2642ccf12afSJon Arne Jørgensen 	R_16_VGATE_STOP, 0x00,
2652ccf12afSJon Arne Jørgensen 	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
2662ccf12afSJon Arne Jørgensen 
2672ccf12afSJon Arne Jørgensen 	0x00, 0x00
2682ccf12afSJon Arne Jørgensen };
2692ccf12afSJon Arne Jørgensen 
27004074f1fSMauro Carvalho Chehab /*
27104074f1fSMauro Carvalho Chehab  * GM7113C is a clone of the SAA7113 chip
27204074f1fSMauro Carvalho Chehab  *  This init table is copied out of the saa7113 datasheet.
27304074f1fSMauro Carvalho Chehab  *  In R_08 we enable "Automatic Field Detection" [AUFD],
27404074f1fSMauro Carvalho Chehab  *  this is disabled when saa711x_set_v4lstd is called.
27504074f1fSMauro Carvalho Chehab  */
2762ccf12afSJon Arne Jørgensen static const unsigned char gm7113c_init[] = {
2772ccf12afSJon Arne Jørgensen 	R_01_INC_DELAY, 0x08,
2782ccf12afSJon Arne Jørgensen 	R_02_INPUT_CNTL_1, 0xc0,
2792ccf12afSJon Arne Jørgensen 	R_03_INPUT_CNTL_2, 0x33,
2802ccf12afSJon Arne Jørgensen 	R_04_INPUT_CNTL_3, 0x00,
2812ccf12afSJon Arne Jørgensen 	R_05_INPUT_CNTL_4, 0x00,
2822ccf12afSJon Arne Jørgensen 	R_06_H_SYNC_START, 0xe9,
2832ccf12afSJon Arne Jørgensen 	R_07_H_SYNC_STOP, 0x0d,
2842ccf12afSJon Arne Jørgensen 	R_08_SYNC_CNTL, 0x98,
2852ccf12afSJon Arne Jørgensen 	R_09_LUMA_CNTL, 0x01,
2862ccf12afSJon Arne Jørgensen 	R_0A_LUMA_BRIGHT_CNTL, 0x80,
2872ccf12afSJon Arne Jørgensen 	R_0B_LUMA_CONTRAST_CNTL, 0x47,
2882ccf12afSJon Arne Jørgensen 	R_0C_CHROMA_SAT_CNTL, 0x40,
2892ccf12afSJon Arne Jørgensen 	R_0D_CHROMA_HUE_CNTL, 0x00,
2902ccf12afSJon Arne Jørgensen 	R_0E_CHROMA_CNTL_1, 0x01,
2912ccf12afSJon Arne Jørgensen 	R_0F_CHROMA_GAIN_CNTL, 0x2a,
2922ccf12afSJon Arne Jørgensen 	R_10_CHROMA_CNTL_2, 0x00,
2932ccf12afSJon Arne Jørgensen 	R_11_MODE_DELAY_CNTL, 0x0c,
2942ccf12afSJon Arne Jørgensen 	R_12_RT_SIGNAL_CNTL, 0x01,
295cb7a01acSMauro Carvalho Chehab 	R_13_RT_X_PORT_OUT_CNTL, 0x00,
296cb7a01acSMauro Carvalho Chehab 	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
297cb7a01acSMauro Carvalho Chehab 	R_15_VGATE_START_FID_CHG, 0x00,
298cb7a01acSMauro Carvalho Chehab 	R_16_VGATE_STOP, 0x00,
299cb7a01acSMauro Carvalho Chehab 	R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
300cb7a01acSMauro Carvalho Chehab 
301cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
302cb7a01acSMauro Carvalho Chehab };
303cb7a01acSMauro Carvalho Chehab 
304cb7a01acSMauro Carvalho Chehab /* If a value differs from the Hauppauge driver values, then the comment starts with
305cb7a01acSMauro Carvalho Chehab    'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
306cb7a01acSMauro Carvalho Chehab    Hauppauge driver sets. */
307cb7a01acSMauro Carvalho Chehab 
308cb7a01acSMauro Carvalho Chehab /* SAA7114 and SAA7115 initialization table */
309cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_init_auto_input[] = {
310cb7a01acSMauro Carvalho Chehab 		/* Front-End Part */
311cb7a01acSMauro Carvalho Chehab 	R_01_INC_DELAY, 0x48,			/* white peak control disabled */
312cb7a01acSMauro Carvalho Chehab 	R_03_INPUT_CNTL_2, 0x20,		/* was 0x30. 0x20: long vertical blanking */
313cb7a01acSMauro Carvalho Chehab 	R_04_INPUT_CNTL_3, 0x90,		/* analog gain set to 0 */
314cb7a01acSMauro Carvalho Chehab 	R_05_INPUT_CNTL_4, 0x90,		/* analog gain set to 0 */
315cb7a01acSMauro Carvalho Chehab 		/* Decoder Part */
316cb7a01acSMauro Carvalho Chehab 	R_06_H_SYNC_START, 0xeb,		/* horiz sync begin = -21 */
317cb7a01acSMauro Carvalho Chehab 	R_07_H_SYNC_STOP, 0xe0,			/* horiz sync stop = -17 */
318cb7a01acSMauro Carvalho Chehab 	R_09_LUMA_CNTL, 0x53,			/* 0x53, was 0x56 for 60hz. luminance control */
319cb7a01acSMauro Carvalho Chehab 	R_0A_LUMA_BRIGHT_CNTL, 0x80,		/* was 0x88. decoder brightness, 0x80 is itu standard */
320cb7a01acSMauro Carvalho Chehab 	R_0B_LUMA_CONTRAST_CNTL, 0x44,		/* was 0x48. decoder contrast, 0x44 is itu standard */
321cb7a01acSMauro Carvalho Chehab 	R_0C_CHROMA_SAT_CNTL, 0x40,		/* was 0x47. decoder saturation, 0x40 is itu standard */
322cb7a01acSMauro Carvalho Chehab 	R_0D_CHROMA_HUE_CNTL, 0x00,
323cb7a01acSMauro Carvalho Chehab 	R_0F_CHROMA_GAIN_CNTL, 0x00,		/* use automatic gain  */
324cb7a01acSMauro Carvalho Chehab 	R_10_CHROMA_CNTL_2, 0x06,		/* chroma: active adaptive combfilter */
325cb7a01acSMauro Carvalho Chehab 	R_11_MODE_DELAY_CNTL, 0x00,
326cb7a01acSMauro Carvalho Chehab 	R_12_RT_SIGNAL_CNTL, 0x9d,		/* RTS0 output control: VGATE */
327cb7a01acSMauro Carvalho Chehab 	R_13_RT_X_PORT_OUT_CNTL, 0x80,		/* ITU656 standard mode, RTCO output enable RTCE */
328cb7a01acSMauro Carvalho Chehab 	R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
329cb7a01acSMauro Carvalho Chehab 	R_18_RAW_DATA_GAIN_CNTL, 0x40,		/* gain 0x00 = nominal */
330cb7a01acSMauro Carvalho Chehab 	R_19_RAW_DATA_OFF_CNTL, 0x80,
331cb7a01acSMauro Carvalho Chehab 	R_1A_COLOR_KILL_LVL_CNTL, 0x77,		/* recommended value */
332cb7a01acSMauro Carvalho Chehab 	R_1B_MISC_TVVCRDET, 0x42,		/* recommended value */
333cb7a01acSMauro Carvalho Chehab 	R_1C_ENHAN_COMB_CTRL1, 0xa9,		/* recommended value */
334cb7a01acSMauro Carvalho Chehab 	R_1D_ENHAN_COMB_CTRL2, 0x01,		/* recommended value */
335cb7a01acSMauro Carvalho Chehab 
336cb7a01acSMauro Carvalho Chehab 
337cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x0,		/* No tasks enabled at init */
338cb7a01acSMauro Carvalho Chehab 
339cb7a01acSMauro Carvalho Chehab 		/* Power Device Control */
340cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset device */
341cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,	/* set device programmed, all in operational mode */
342cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
343cb7a01acSMauro Carvalho Chehab };
344cb7a01acSMauro Carvalho Chehab 
345cb7a01acSMauro Carvalho Chehab /* Used to reset saa7113, saa7114 and saa7115 */
346cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_cfg_reset_scaler[] = {
347cb7a01acSMauro Carvalho Chehab 	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00,	/* disable I-port output */
348cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
349cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
350cb7a01acSMauro Carvalho Chehab 	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* enable I-port output */
351cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
352cb7a01acSMauro Carvalho Chehab };
353cb7a01acSMauro Carvalho Chehab 
354cb7a01acSMauro Carvalho Chehab /* ============== SAA7715 VIDEO templates =============  */
355cb7a01acSMauro Carvalho Chehab 
356cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_cfg_60hz_video[] = {
357cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
358cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
359cb7a01acSMauro Carvalho Chehab 
360cb7a01acSMauro Carvalho Chehab 	R_15_VGATE_START_FID_CHG, 0x03,
361cb7a01acSMauro Carvalho Chehab 	R_16_VGATE_STOP, 0x11,
362cb7a01acSMauro Carvalho Chehab 	R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
363cb7a01acSMauro Carvalho Chehab 
364cb7a01acSMauro Carvalho Chehab 	R_08_SYNC_CNTL, 0x68,			/* 0xBO: auto detection, 0x68 = NTSC */
365cb7a01acSMauro Carvalho Chehab 	R_0E_CHROMA_CNTL_1, 0x07,		/* video autodetection is on */
366cb7a01acSMauro Carvalho Chehab 
367cb7a01acSMauro Carvalho Chehab 	R_5A_V_OFF_FOR_SLICER, 0x06,		/* standard 60hz value for ITU656 line counting */
368cb7a01acSMauro Carvalho Chehab 
369cb7a01acSMauro Carvalho Chehab 	/* Task A */
370cb7a01acSMauro Carvalho Chehab 	R_90_A_TASK_HANDLING_CNTL, 0x80,
371cb7a01acSMauro Carvalho Chehab 	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
372cb7a01acSMauro Carvalho Chehab 	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
373cb7a01acSMauro Carvalho Chehab 	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
374cb7a01acSMauro Carvalho Chehab 
375cb7a01acSMauro Carvalho Chehab 	/* hoffset low (input), 0x0002 is minimum */
376cb7a01acSMauro Carvalho Chehab 	R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
377cb7a01acSMauro Carvalho Chehab 	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
378cb7a01acSMauro Carvalho Chehab 
379cb7a01acSMauro Carvalho Chehab 	/* hsize low (input), 0x02d0 = 720 */
380cb7a01acSMauro Carvalho Chehab 	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
381cb7a01acSMauro Carvalho Chehab 	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
382cb7a01acSMauro Carvalho Chehab 
383cb7a01acSMauro Carvalho Chehab 	R_98_A_VERT_INPUT_WINDOW_START, 0x05,
384cb7a01acSMauro Carvalho Chehab 	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
385cb7a01acSMauro Carvalho Chehab 
386cb7a01acSMauro Carvalho Chehab 	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
387cb7a01acSMauro Carvalho Chehab 	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
388cb7a01acSMauro Carvalho Chehab 
389cb7a01acSMauro Carvalho Chehab 	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
390cb7a01acSMauro Carvalho Chehab 	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
391cb7a01acSMauro Carvalho Chehab 
392cb7a01acSMauro Carvalho Chehab 	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
393cb7a01acSMauro Carvalho Chehab 	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
394cb7a01acSMauro Carvalho Chehab 
395cb7a01acSMauro Carvalho Chehab 	/* Task B */
396cb7a01acSMauro Carvalho Chehab 	R_C0_B_TASK_HANDLING_CNTL, 0x00,
397cb7a01acSMauro Carvalho Chehab 	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
398cb7a01acSMauro Carvalho Chehab 	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
399cb7a01acSMauro Carvalho Chehab 	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
400cb7a01acSMauro Carvalho Chehab 
401cb7a01acSMauro Carvalho Chehab 	/* 0x0002 is minimum */
402cb7a01acSMauro Carvalho Chehab 	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
403cb7a01acSMauro Carvalho Chehab 	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
404cb7a01acSMauro Carvalho Chehab 
405cb7a01acSMauro Carvalho Chehab 	/* 0x02d0 = 720 */
406cb7a01acSMauro Carvalho Chehab 	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
407cb7a01acSMauro Carvalho Chehab 	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
408cb7a01acSMauro Carvalho Chehab 
409cb7a01acSMauro Carvalho Chehab 	/* vwindow start 0x12 = 18 */
410cb7a01acSMauro Carvalho Chehab 	R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
411cb7a01acSMauro Carvalho Chehab 	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
412cb7a01acSMauro Carvalho Chehab 
413cb7a01acSMauro Carvalho Chehab 	/* vwindow length 0xf8 = 248 */
414cb7a01acSMauro Carvalho Chehab 	R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
415cb7a01acSMauro Carvalho Chehab 	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
416cb7a01acSMauro Carvalho Chehab 
417cb7a01acSMauro Carvalho Chehab 	/* hwindow 0x02d0 = 720 */
418cb7a01acSMauro Carvalho Chehab 	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
419cb7a01acSMauro Carvalho Chehab 	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
420cb7a01acSMauro Carvalho Chehab 
421cb7a01acSMauro Carvalho Chehab 	R_F0_LFCO_PER_LINE, 0xad,		/* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
422cb7a01acSMauro Carvalho Chehab 	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0 */
423cb7a01acSMauro Carvalho Chehab 	R_F5_PULSGEN_LINE_LENGTH, 0xad,
424cb7a01acSMauro Carvalho Chehab 	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
425cb7a01acSMauro Carvalho Chehab 
426cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
427cb7a01acSMauro Carvalho Chehab };
428cb7a01acSMauro Carvalho Chehab 
429cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_cfg_50hz_video[] = {
430cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x00,
431cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,	/* reset scaler */
432cb7a01acSMauro Carvalho Chehab 
433cb7a01acSMauro Carvalho Chehab 	R_15_VGATE_START_FID_CHG, 0x37,		/* VGATE start */
434cb7a01acSMauro Carvalho Chehab 	R_16_VGATE_STOP, 0x16,
435cb7a01acSMauro Carvalho Chehab 	R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
436cb7a01acSMauro Carvalho Chehab 
437cb7a01acSMauro Carvalho Chehab 	R_08_SYNC_CNTL, 0x28,			/* 0x28 = PAL */
438cb7a01acSMauro Carvalho Chehab 	R_0E_CHROMA_CNTL_1, 0x07,
439cb7a01acSMauro Carvalho Chehab 
440cb7a01acSMauro Carvalho Chehab 	R_5A_V_OFF_FOR_SLICER, 0x03,		/* standard 50hz value */
441cb7a01acSMauro Carvalho Chehab 
442cb7a01acSMauro Carvalho Chehab 	/* Task A */
443cb7a01acSMauro Carvalho Chehab 	R_90_A_TASK_HANDLING_CNTL, 0x81,
444cb7a01acSMauro Carvalho Chehab 	R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
445cb7a01acSMauro Carvalho Chehab 	R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
446cb7a01acSMauro Carvalho Chehab 	R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
447cb7a01acSMauro Carvalho Chehab 
448cb7a01acSMauro Carvalho Chehab 	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
449cb7a01acSMauro Carvalho Chehab 	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
450cb7a01acSMauro Carvalho Chehab 	/* hoffset low (input), 0x0002 is minimum */
451cb7a01acSMauro Carvalho Chehab 	R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
452cb7a01acSMauro Carvalho Chehab 	R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
453cb7a01acSMauro Carvalho Chehab 
454cb7a01acSMauro Carvalho Chehab 	/* hsize low (input), 0x02d0 = 720 */
455cb7a01acSMauro Carvalho Chehab 	R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
456cb7a01acSMauro Carvalho Chehab 	R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
457cb7a01acSMauro Carvalho Chehab 
458cb7a01acSMauro Carvalho Chehab 	R_98_A_VERT_INPUT_WINDOW_START, 0x03,
459cb7a01acSMauro Carvalho Chehab 	R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
460cb7a01acSMauro Carvalho Chehab 
461cb7a01acSMauro Carvalho Chehab 	/* vsize 0x12 = 18 */
462cb7a01acSMauro Carvalho Chehab 	R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
463cb7a01acSMauro Carvalho Chehab 	R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
464cb7a01acSMauro Carvalho Chehab 
465cb7a01acSMauro Carvalho Chehab 	/* hsize 0x05a0 = 1440 */
466cb7a01acSMauro Carvalho Chehab 	R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
467cb7a01acSMauro Carvalho Chehab 	R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,	/* hsize hi (output) */
468cb7a01acSMauro Carvalho Chehab 	R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12,		/* vsize low (output), 0x12 = 18 */
469cb7a01acSMauro Carvalho Chehab 	R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,	/* vsize hi (output) */
470cb7a01acSMauro Carvalho Chehab 
471cb7a01acSMauro Carvalho Chehab 	/* Task B */
472cb7a01acSMauro Carvalho Chehab 	R_C0_B_TASK_HANDLING_CNTL, 0x00,
473cb7a01acSMauro Carvalho Chehab 	R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
474cb7a01acSMauro Carvalho Chehab 	R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
475cb7a01acSMauro Carvalho Chehab 	R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
476cb7a01acSMauro Carvalho Chehab 
477cb7a01acSMauro Carvalho Chehab 	/* This is weird: the datasheet says that you should use 2 as the minimum value, */
478cb7a01acSMauro Carvalho Chehab 	/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
479cb7a01acSMauro Carvalho Chehab 	/* hoffset low (input), 0x0002 is minimum. See comment above. */
480cb7a01acSMauro Carvalho Chehab 	R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
481cb7a01acSMauro Carvalho Chehab 	R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
482cb7a01acSMauro Carvalho Chehab 
483cb7a01acSMauro Carvalho Chehab 	/* hsize 0x02d0 = 720 */
484cb7a01acSMauro Carvalho Chehab 	R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
485cb7a01acSMauro Carvalho Chehab 	R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
486cb7a01acSMauro Carvalho Chehab 
487cb7a01acSMauro Carvalho Chehab 	/* voffset 0x16 = 22 */
488cb7a01acSMauro Carvalho Chehab 	R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
489cb7a01acSMauro Carvalho Chehab 	R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
490cb7a01acSMauro Carvalho Chehab 
491cb7a01acSMauro Carvalho Chehab 	/* vsize 0x0120 = 288 */
492cb7a01acSMauro Carvalho Chehab 	R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
493cb7a01acSMauro Carvalho Chehab 	R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
494cb7a01acSMauro Carvalho Chehab 
495cb7a01acSMauro Carvalho Chehab 	/* hsize 0x02d0 = 720 */
496cb7a01acSMauro Carvalho Chehab 	R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
497cb7a01acSMauro Carvalho Chehab 	R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
498cb7a01acSMauro Carvalho Chehab 
499cb7a01acSMauro Carvalho Chehab 	R_F0_LFCO_PER_LINE, 0xb0,		/* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
500cb7a01acSMauro Carvalho Chehab 	R_F1_P_I_PARAM_SELECT, 0x05,		/* low bit with 0xF0, (was 0x05) */
501cb7a01acSMauro Carvalho Chehab 	R_F5_PULSGEN_LINE_LENGTH, 0xb0,
502cb7a01acSMauro Carvalho Chehab 	R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
503cb7a01acSMauro Carvalho Chehab 
504cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
505cb7a01acSMauro Carvalho Chehab };
506cb7a01acSMauro Carvalho Chehab 
507cb7a01acSMauro Carvalho Chehab /* ============== SAA7715 VIDEO templates (end) =======  */
508cb7a01acSMauro Carvalho Chehab 
509cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_cfg_vbi_on[] = {
510cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
511cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
512cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x30,			/* Activate both tasks */
513cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
514cb7a01acSMauro Carvalho Chehab 	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
515cb7a01acSMauro Carvalho Chehab 
516cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
517cb7a01acSMauro Carvalho Chehab };
518cb7a01acSMauro Carvalho Chehab 
519cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_cfg_vbi_off[] = {
520cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x00,			/* reset tasks */
521cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,		/* reset scaler */
522cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x20,			/* Activate only task "B" */
523cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,		/* activate scaler */
524cb7a01acSMauro Carvalho Chehab 	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,	/* Enable I-port output */
525cb7a01acSMauro Carvalho Chehab 
526cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
527cb7a01acSMauro Carvalho Chehab };
528cb7a01acSMauro Carvalho Chehab 
529cb7a01acSMauro Carvalho Chehab 
530cb7a01acSMauro Carvalho Chehab static const unsigned char saa7115_init_misc[] = {
531cb7a01acSMauro Carvalho Chehab 	R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
532cb7a01acSMauro Carvalho Chehab 	R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
533cb7a01acSMauro Carvalho Chehab 	R_84_I_PORT_SIGNAL_DEF, 0x20,
534cb7a01acSMauro Carvalho Chehab 	R_85_I_PORT_SIGNAL_POLAR, 0x21,
535cb7a01acSMauro Carvalho Chehab 	R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
536cb7a01acSMauro Carvalho Chehab 	R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
537cb7a01acSMauro Carvalho Chehab 
538cb7a01acSMauro Carvalho Chehab 	/* Task A */
539cb7a01acSMauro Carvalho Chehab 	R_A0_A_HORIZ_PRESCALING, 0x01,
540cb7a01acSMauro Carvalho Chehab 	R_A1_A_ACCUMULATION_LENGTH, 0x00,
541cb7a01acSMauro Carvalho Chehab 	R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
542cb7a01acSMauro Carvalho Chehab 
543cb7a01acSMauro Carvalho Chehab 	/* Configure controls at nominal value*/
544cb7a01acSMauro Carvalho Chehab 	R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
545cb7a01acSMauro Carvalho Chehab 	R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
546cb7a01acSMauro Carvalho Chehab 	R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
547cb7a01acSMauro Carvalho Chehab 
548cb7a01acSMauro Carvalho Chehab 	/* note: 2 x zoom ensures that VBI lines have same length as video lines. */
549cb7a01acSMauro Carvalho Chehab 	R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
550cb7a01acSMauro Carvalho Chehab 	R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
551cb7a01acSMauro Carvalho Chehab 
552cb7a01acSMauro Carvalho Chehab 	R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
553cb7a01acSMauro Carvalho Chehab 
554cb7a01acSMauro Carvalho Chehab 	/* must be horiz lum scaling / 2 */
555cb7a01acSMauro Carvalho Chehab 	R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
556cb7a01acSMauro Carvalho Chehab 	R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
557cb7a01acSMauro Carvalho Chehab 
558cb7a01acSMauro Carvalho Chehab 	/* must be offset luma / 2 */
559cb7a01acSMauro Carvalho Chehab 	R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
560cb7a01acSMauro Carvalho Chehab 
561cb7a01acSMauro Carvalho Chehab 	R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
562cb7a01acSMauro Carvalho Chehab 	R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
563cb7a01acSMauro Carvalho Chehab 
564cb7a01acSMauro Carvalho Chehab 	R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
565cb7a01acSMauro Carvalho Chehab 	R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
566cb7a01acSMauro Carvalho Chehab 
567cb7a01acSMauro Carvalho Chehab 	R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
568cb7a01acSMauro Carvalho Chehab 
569cb7a01acSMauro Carvalho Chehab 	R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
570cb7a01acSMauro Carvalho Chehab 	R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
571cb7a01acSMauro Carvalho Chehab 	R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
572cb7a01acSMauro Carvalho Chehab 	R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
573cb7a01acSMauro Carvalho Chehab 
574cb7a01acSMauro Carvalho Chehab 	R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
575cb7a01acSMauro Carvalho Chehab 	R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
576cb7a01acSMauro Carvalho Chehab 	R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
577cb7a01acSMauro Carvalho Chehab 	R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
578cb7a01acSMauro Carvalho Chehab 
579cb7a01acSMauro Carvalho Chehab 	/* Task B */
580cb7a01acSMauro Carvalho Chehab 	R_D0_B_HORIZ_PRESCALING, 0x01,
581cb7a01acSMauro Carvalho Chehab 	R_D1_B_ACCUMULATION_LENGTH, 0x00,
582cb7a01acSMauro Carvalho Chehab 	R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
583cb7a01acSMauro Carvalho Chehab 
584cb7a01acSMauro Carvalho Chehab 	/* Configure controls at nominal value*/
585cb7a01acSMauro Carvalho Chehab 	R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
586cb7a01acSMauro Carvalho Chehab 	R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
587cb7a01acSMauro Carvalho Chehab 	R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
588cb7a01acSMauro Carvalho Chehab 
589cb7a01acSMauro Carvalho Chehab 	/* hor lum scaling 0x0400 = 1 */
590cb7a01acSMauro Carvalho Chehab 	R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
591cb7a01acSMauro Carvalho Chehab 	R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
592cb7a01acSMauro Carvalho Chehab 
593cb7a01acSMauro Carvalho Chehab 	R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
594cb7a01acSMauro Carvalho Chehab 
595cb7a01acSMauro Carvalho Chehab 	/* must be hor lum scaling / 2 */
596cb7a01acSMauro Carvalho Chehab 	R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
597cb7a01acSMauro Carvalho Chehab 	R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
598cb7a01acSMauro Carvalho Chehab 
599cb7a01acSMauro Carvalho Chehab 	/* must be offset luma / 2 */
600cb7a01acSMauro Carvalho Chehab 	R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
601cb7a01acSMauro Carvalho Chehab 
602cb7a01acSMauro Carvalho Chehab 	R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
603cb7a01acSMauro Carvalho Chehab 	R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
604cb7a01acSMauro Carvalho Chehab 
605cb7a01acSMauro Carvalho Chehab 	R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
606cb7a01acSMauro Carvalho Chehab 	R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
607cb7a01acSMauro Carvalho Chehab 
608cb7a01acSMauro Carvalho Chehab 	R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
609cb7a01acSMauro Carvalho Chehab 
610cb7a01acSMauro Carvalho Chehab 	R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
611cb7a01acSMauro Carvalho Chehab 	R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
612cb7a01acSMauro Carvalho Chehab 	R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
613cb7a01acSMauro Carvalho Chehab 	R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
614cb7a01acSMauro Carvalho Chehab 
615cb7a01acSMauro Carvalho Chehab 	R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
616cb7a01acSMauro Carvalho Chehab 	R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
617cb7a01acSMauro Carvalho Chehab 	R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
618cb7a01acSMauro Carvalho Chehab 	R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
619cb7a01acSMauro Carvalho Chehab 
620cb7a01acSMauro Carvalho Chehab 	R_F2_NOMINAL_PLL2_DTO, 0x50,		/* crystal clock = 24.576 MHz, target = 27MHz */
621cb7a01acSMauro Carvalho Chehab 	R_F3_PLL_INCREMENT, 0x46,
622cb7a01acSMauro Carvalho Chehab 	R_F4_PLL2_STATUS, 0x00,
623cb7a01acSMauro Carvalho Chehab 	R_F7_PULSE_A_POS_MSB, 0x4b,		/* not the recommended settings! */
624cb7a01acSMauro Carvalho Chehab 	R_F8_PULSE_B_POS, 0x00,
625cb7a01acSMauro Carvalho Chehab 	R_F9_PULSE_B_POS_MSB, 0x4b,
626cb7a01acSMauro Carvalho Chehab 	R_FA_PULSE_C_POS, 0x00,
627cb7a01acSMauro Carvalho Chehab 	R_FB_PULSE_C_POS_MSB, 0x4b,
628cb7a01acSMauro Carvalho Chehab 
629cb7a01acSMauro Carvalho Chehab 	/* PLL2 lock detection settings: 71 lines 50% phase error */
630cb7a01acSMauro Carvalho Chehab 	R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
631cb7a01acSMauro Carvalho Chehab 
632cb7a01acSMauro Carvalho Chehab 	/* Turn off VBI */
633cb7a01acSMauro Carvalho Chehab 	R_40_SLICER_CNTL_1, 0x20,             /* No framing code errors allowed. */
634cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE, 0xff,
635cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+1, 0xff,
636cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+2, 0xff,
637cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+3, 0xff,
638cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+4, 0xff,
639cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+5, 0xff,
640cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+6, 0xff,
641cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+7, 0xff,
642cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+8, 0xff,
643cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+9, 0xff,
644cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+10, 0xff,
645cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+11, 0xff,
646cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+12, 0xff,
647cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+13, 0xff,
648cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+14, 0xff,
649cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+15, 0xff,
650cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+16, 0xff,
651cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+17, 0xff,
652cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+18, 0xff,
653cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+19, 0xff,
654cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+20, 0xff,
655cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+21, 0xff,
656cb7a01acSMauro Carvalho Chehab 	R_41_LCR_BASE+22, 0xff,
657cb7a01acSMauro Carvalho Chehab 	R_58_PROGRAM_FRAMING_CODE, 0x40,
658cb7a01acSMauro Carvalho Chehab 	R_59_H_OFF_FOR_SLICER, 0x47,
659cb7a01acSMauro Carvalho Chehab 	R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
660cb7a01acSMauro Carvalho Chehab 	R_5D_DID, 0xbd,
661cb7a01acSMauro Carvalho Chehab 	R_5E_SDID, 0x35,
662cb7a01acSMauro Carvalho Chehab 
663cb7a01acSMauro Carvalho Chehab 	R_02_INPUT_CNTL_1, 0xc4, /* input tuner -> input 4, amplifier active */
664cb7a01acSMauro Carvalho Chehab 
665cb7a01acSMauro Carvalho Chehab 	R_80_GLOBAL_CNTL_1, 0x20,		/* enable task B */
666cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
667cb7a01acSMauro Carvalho Chehab 	R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
668cb7a01acSMauro Carvalho Chehab 	0x00, 0x00
669cb7a01acSMauro Carvalho Chehab };
670cb7a01acSMauro Carvalho Chehab 
671cb7a01acSMauro Carvalho Chehab static int saa711x_odd_parity(u8 c)
672cb7a01acSMauro Carvalho Chehab {
673cb7a01acSMauro Carvalho Chehab 	c ^= (c >> 4);
674cb7a01acSMauro Carvalho Chehab 	c ^= (c >> 2);
675cb7a01acSMauro Carvalho Chehab 	c ^= (c >> 1);
676cb7a01acSMauro Carvalho Chehab 
677cb7a01acSMauro Carvalho Chehab 	return c & 1;
678cb7a01acSMauro Carvalho Chehab }
679cb7a01acSMauro Carvalho Chehab 
680cb7a01acSMauro Carvalho Chehab static int saa711x_decode_vps(u8 *dst, u8 *p)
681cb7a01acSMauro Carvalho Chehab {
682cb7a01acSMauro Carvalho Chehab 	static const u8 biphase_tbl[] = {
683cb7a01acSMauro Carvalho Chehab 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
684cb7a01acSMauro Carvalho Chehab 		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
685cb7a01acSMauro Carvalho Chehab 		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
686cb7a01acSMauro Carvalho Chehab 		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
687cb7a01acSMauro Carvalho Chehab 		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
688cb7a01acSMauro Carvalho Chehab 		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
689cb7a01acSMauro Carvalho Chehab 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
690cb7a01acSMauro Carvalho Chehab 		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
691cb7a01acSMauro Carvalho Chehab 		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
692cb7a01acSMauro Carvalho Chehab 		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
693cb7a01acSMauro Carvalho Chehab 		0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
694cb7a01acSMauro Carvalho Chehab 		0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
695cb7a01acSMauro Carvalho Chehab 		0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
696cb7a01acSMauro Carvalho Chehab 		0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
697cb7a01acSMauro Carvalho Chehab 		0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
698cb7a01acSMauro Carvalho Chehab 		0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
699cb7a01acSMauro Carvalho Chehab 		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
700cb7a01acSMauro Carvalho Chehab 		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
701cb7a01acSMauro Carvalho Chehab 		0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
702cb7a01acSMauro Carvalho Chehab 		0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
703cb7a01acSMauro Carvalho Chehab 		0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
704cb7a01acSMauro Carvalho Chehab 		0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
705cb7a01acSMauro Carvalho Chehab 		0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
706cb7a01acSMauro Carvalho Chehab 		0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
707cb7a01acSMauro Carvalho Chehab 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
708cb7a01acSMauro Carvalho Chehab 		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
709cb7a01acSMauro Carvalho Chehab 		0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
710cb7a01acSMauro Carvalho Chehab 		0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
711cb7a01acSMauro Carvalho Chehab 		0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
712cb7a01acSMauro Carvalho Chehab 		0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
713cb7a01acSMauro Carvalho Chehab 		0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
714cb7a01acSMauro Carvalho Chehab 		0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
715cb7a01acSMauro Carvalho Chehab 	};
716cb7a01acSMauro Carvalho Chehab 	int i;
717cb7a01acSMauro Carvalho Chehab 	u8 c, err = 0;
718cb7a01acSMauro Carvalho Chehab 
719cb7a01acSMauro Carvalho Chehab 	for (i = 0; i < 2 * 13; i += 2) {
720cb7a01acSMauro Carvalho Chehab 		err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
721cb7a01acSMauro Carvalho Chehab 		c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
722cb7a01acSMauro Carvalho Chehab 		dst[i / 2] = c;
723cb7a01acSMauro Carvalho Chehab 	}
724cb7a01acSMauro Carvalho Chehab 	return err & 0xf0;
725cb7a01acSMauro Carvalho Chehab }
726cb7a01acSMauro Carvalho Chehab 
727cb7a01acSMauro Carvalho Chehab static int saa711x_decode_wss(u8 *p)
728cb7a01acSMauro Carvalho Chehab {
729cb7a01acSMauro Carvalho Chehab 	static const int wss_bits[8] = {
730cb7a01acSMauro Carvalho Chehab 		0, 0, 0, 1, 0, 1, 1, 1
731cb7a01acSMauro Carvalho Chehab 	};
732cb7a01acSMauro Carvalho Chehab 	unsigned char parity;
733cb7a01acSMauro Carvalho Chehab 	int wss = 0;
734cb7a01acSMauro Carvalho Chehab 	int i;
735cb7a01acSMauro Carvalho Chehab 
736cb7a01acSMauro Carvalho Chehab 	for (i = 0; i < 16; i++) {
737cb7a01acSMauro Carvalho Chehab 		int b1 = wss_bits[p[i] & 7];
738cb7a01acSMauro Carvalho Chehab 		int b2 = wss_bits[(p[i] >> 3) & 7];
739cb7a01acSMauro Carvalho Chehab 
740cb7a01acSMauro Carvalho Chehab 		if (b1 == b2)
741cb7a01acSMauro Carvalho Chehab 			return -1;
742cb7a01acSMauro Carvalho Chehab 		wss |= b2 << i;
743cb7a01acSMauro Carvalho Chehab 	}
744cb7a01acSMauro Carvalho Chehab 	parity = wss & 15;
745cb7a01acSMauro Carvalho Chehab 	parity ^= parity >> 2;
746cb7a01acSMauro Carvalho Chehab 	parity ^= parity >> 1;
747cb7a01acSMauro Carvalho Chehab 
748cb7a01acSMauro Carvalho Chehab 	if (!(parity & 1))
749cb7a01acSMauro Carvalho Chehab 		return -1;
750cb7a01acSMauro Carvalho Chehab 
751cb7a01acSMauro Carvalho Chehab 	return wss;
752cb7a01acSMauro Carvalho Chehab }
753cb7a01acSMauro Carvalho Chehab 
754cb7a01acSMauro Carvalho Chehab static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
755cb7a01acSMauro Carvalho Chehab {
756cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
757cb7a01acSMauro Carvalho Chehab 	u32 acpf;
758cb7a01acSMauro Carvalho Chehab 	u32 acni;
759cb7a01acSMauro Carvalho Chehab 	u32 hz;
760cb7a01acSMauro Carvalho Chehab 	u64 f;
761cb7a01acSMauro Carvalho Chehab 	u8 acc = 0; 	/* reg 0x3a, audio clock control */
762cb7a01acSMauro Carvalho Chehab 
763cb7a01acSMauro Carvalho Chehab 	/* Checks for chips that don't have audio clock (saa7111, saa7113) */
764cb7a01acSMauro Carvalho Chehab 	if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
765cb7a01acSMauro Carvalho Chehab 		return 0;
766cb7a01acSMauro Carvalho Chehab 
767cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
768cb7a01acSMauro Carvalho Chehab 
769cb7a01acSMauro Carvalho Chehab 	/* sanity check */
770cb7a01acSMauro Carvalho Chehab 	if (freq < 32000 || freq > 48000)
771cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
772cb7a01acSMauro Carvalho Chehab 
773cb7a01acSMauro Carvalho Chehab 	/* hz is the refresh rate times 100 */
774cb7a01acSMauro Carvalho Chehab 	hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
775cb7a01acSMauro Carvalho Chehab 	/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
776cb7a01acSMauro Carvalho Chehab 	acpf = (25600 * freq) / hz;
777cb7a01acSMauro Carvalho Chehab 	/* acni = (256 * freq * 2^23) / crystal_frequency =
778cb7a01acSMauro Carvalho Chehab 		  (freq * 2^(8+23)) / crystal_frequency =
779cb7a01acSMauro Carvalho Chehab 		  (freq << 31) / crystal_frequency */
780cb7a01acSMauro Carvalho Chehab 	f = freq;
781cb7a01acSMauro Carvalho Chehab 	f = f << 31;
782cb7a01acSMauro Carvalho Chehab 	do_div(f, state->crystal_freq);
783cb7a01acSMauro Carvalho Chehab 	acni = f;
784cb7a01acSMauro Carvalho Chehab 	if (state->ucgc) {
785cb7a01acSMauro Carvalho Chehab 		acpf = acpf * state->cgcdiv / 16;
786cb7a01acSMauro Carvalho Chehab 		acni = acni * state->cgcdiv / 16;
787cb7a01acSMauro Carvalho Chehab 		acc = 0x80;
788cb7a01acSMauro Carvalho Chehab 		if (state->cgcdiv == 3)
789cb7a01acSMauro Carvalho Chehab 			acc |= 0x40;
790cb7a01acSMauro Carvalho Chehab 	}
791cb7a01acSMauro Carvalho Chehab 	if (state->apll)
792cb7a01acSMauro Carvalho Chehab 		acc |= 0x08;
793cb7a01acSMauro Carvalho Chehab 
7941589037fSHans Verkuil 	if (state->double_asclk) {
7951589037fSHans Verkuil 		acpf <<= 1;
7961589037fSHans Verkuil 		acni <<= 1;
7971589037fSHans Verkuil 	}
798cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
7991589037fSHans Verkuil 	saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10 << state->double_asclk);
800cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
801cb7a01acSMauro Carvalho Chehab 
802cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
803cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
804cb7a01acSMauro Carvalho Chehab 							(acpf >> 8) & 0xff);
805cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
806cb7a01acSMauro Carvalho Chehab 							(acpf >> 16) & 0x03);
807cb7a01acSMauro Carvalho Chehab 
808cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
809cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
810cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
811cb7a01acSMauro Carvalho Chehab 	state->audclk_freq = freq;
812cb7a01acSMauro Carvalho Chehab 	return 0;
813cb7a01acSMauro Carvalho Chehab }
814cb7a01acSMauro Carvalho Chehab 
815cb7a01acSMauro Carvalho Chehab static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
816cb7a01acSMauro Carvalho Chehab {
817cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
818cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
819cb7a01acSMauro Carvalho Chehab 
820cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
821cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CHROMA_AGC:
822cb7a01acSMauro Carvalho Chehab 		/* chroma gain cluster */
823cb7a01acSMauro Carvalho Chehab 		if (state->agc->val)
824cb7a01acSMauro Carvalho Chehab 			state->gain->val =
825cb7a01acSMauro Carvalho Chehab 				saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
826cb7a01acSMauro Carvalho Chehab 		break;
827cb7a01acSMauro Carvalho Chehab 	}
828cb7a01acSMauro Carvalho Chehab 	return 0;
829cb7a01acSMauro Carvalho Chehab }
830cb7a01acSMauro Carvalho Chehab 
831cb7a01acSMauro Carvalho Chehab static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl)
832cb7a01acSMauro Carvalho Chehab {
833cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
834cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
835cb7a01acSMauro Carvalho Chehab 
836cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
837cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
838cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, ctrl->val);
839cb7a01acSMauro Carvalho Chehab 		break;
840cb7a01acSMauro Carvalho Chehab 
841cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
842cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, ctrl->val);
843cb7a01acSMauro Carvalho Chehab 		break;
844cb7a01acSMauro Carvalho Chehab 
845cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
846cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, ctrl->val);
847cb7a01acSMauro Carvalho Chehab 		break;
848cb7a01acSMauro Carvalho Chehab 
849cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
850cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, ctrl->val);
851cb7a01acSMauro Carvalho Chehab 		break;
852cb7a01acSMauro Carvalho Chehab 
853cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CHROMA_AGC:
854cb7a01acSMauro Carvalho Chehab 		/* chroma gain cluster */
855cb7a01acSMauro Carvalho Chehab 		if (state->agc->val)
856cb7a01acSMauro Carvalho Chehab 			saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val);
857cb7a01acSMauro Carvalho Chehab 		else
858cb7a01acSMauro Carvalho Chehab 			saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80);
859cb7a01acSMauro Carvalho Chehab 		break;
860cb7a01acSMauro Carvalho Chehab 
861cb7a01acSMauro Carvalho Chehab 	default:
862cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
863cb7a01acSMauro Carvalho Chehab 	}
864cb7a01acSMauro Carvalho Chehab 
865cb7a01acSMauro Carvalho Chehab 	return 0;
866cb7a01acSMauro Carvalho Chehab }
867cb7a01acSMauro Carvalho Chehab 
868cb7a01acSMauro Carvalho Chehab static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
869cb7a01acSMauro Carvalho Chehab {
870cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
871cb7a01acSMauro Carvalho Chehab 	int HPSC, HFSC;
872cb7a01acSMauro Carvalho Chehab 	int VSCY;
873cb7a01acSMauro Carvalho Chehab 	int res;
874cb7a01acSMauro Carvalho Chehab 	int is_50hz = state->std & V4L2_STD_625_50;
875cb7a01acSMauro Carvalho Chehab 	int Vsrc = is_50hz ? 576 : 480;
876cb7a01acSMauro Carvalho Chehab 
877cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
878cb7a01acSMauro Carvalho Chehab 
879cb7a01acSMauro Carvalho Chehab 	/* FIXME need better bounds checking here */
880cb7a01acSMauro Carvalho Chehab 	if ((width < 1) || (width > 1440))
881cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
882cb7a01acSMauro Carvalho Chehab 	if ((height < 1) || (height > Vsrc))
883cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
884cb7a01acSMauro Carvalho Chehab 
885cb7a01acSMauro Carvalho Chehab 	if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
886cb7a01acSMauro Carvalho Chehab 		/* Decoder only supports 720 columns and 480 or 576 lines */
887cb7a01acSMauro Carvalho Chehab 		if (width != 720)
888cb7a01acSMauro Carvalho Chehab 			return -EINVAL;
889cb7a01acSMauro Carvalho Chehab 		if (height != Vsrc)
890cb7a01acSMauro Carvalho Chehab 			return -EINVAL;
891cb7a01acSMauro Carvalho Chehab 	}
892cb7a01acSMauro Carvalho Chehab 
893cb7a01acSMauro Carvalho Chehab 	state->width = width;
894cb7a01acSMauro Carvalho Chehab 	state->height = height;
895cb7a01acSMauro Carvalho Chehab 
896cb7a01acSMauro Carvalho Chehab 	if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
897cb7a01acSMauro Carvalho Chehab 		return 0;
898cb7a01acSMauro Carvalho Chehab 
899cb7a01acSMauro Carvalho Chehab 	/* probably have a valid size, let's set it */
900cb7a01acSMauro Carvalho Chehab 	/* Set output width/height */
901cb7a01acSMauro Carvalho Chehab 	/* width */
902cb7a01acSMauro Carvalho Chehab 
903cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
904cb7a01acSMauro Carvalho Chehab 					(u8) (width & 0xff));
905cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
906cb7a01acSMauro Carvalho Chehab 					(u8) ((width >> 8) & 0xff));
907cb7a01acSMauro Carvalho Chehab 
908cb7a01acSMauro Carvalho Chehab 	/* Vertical Scaling uses height/2 */
909cb7a01acSMauro Carvalho Chehab 	res = height / 2;
910cb7a01acSMauro Carvalho Chehab 
911cb7a01acSMauro Carvalho Chehab 	/* On 60Hz, it is using a higher Vertical Output Size */
912cb7a01acSMauro Carvalho Chehab 	if (!is_50hz)
913cb7a01acSMauro Carvalho Chehab 		res += (VRES_60HZ - 480) >> 1;
914cb7a01acSMauro Carvalho Chehab 
915cb7a01acSMauro Carvalho Chehab 		/* height */
916cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
917cb7a01acSMauro Carvalho Chehab 					(u8) (res & 0xff));
918cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
919cb7a01acSMauro Carvalho Chehab 					(u8) ((res >> 8) & 0xff));
920cb7a01acSMauro Carvalho Chehab 
921cb7a01acSMauro Carvalho Chehab 	/* Scaling settings */
922cb7a01acSMauro Carvalho Chehab 	/* Hprescaler is floor(inres/outres) */
923cb7a01acSMauro Carvalho Chehab 	HPSC = (int)(720 / width);
924cb7a01acSMauro Carvalho Chehab 	/* 0 is not allowed (div. by zero) */
925cb7a01acSMauro Carvalho Chehab 	HPSC = HPSC ? HPSC : 1;
926cb7a01acSMauro Carvalho Chehab 	HFSC = (int)((1024 * 720) / (HPSC * width));
927cb7a01acSMauro Carvalho Chehab 	/* FIXME hardcodes to "Task B"
928cb7a01acSMauro Carvalho Chehab 	 * write H prescaler integer */
929cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
930cb7a01acSMauro Carvalho Chehab 				(u8) (HPSC & 0x3f));
931cb7a01acSMauro Carvalho Chehab 
932cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
933cb7a01acSMauro Carvalho Chehab 	/* write H fine-scaling (luminance) */
934cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
935cb7a01acSMauro Carvalho Chehab 				(u8) (HFSC & 0xff));
936cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
937cb7a01acSMauro Carvalho Chehab 				(u8) ((HFSC >> 8) & 0xff));
938cb7a01acSMauro Carvalho Chehab 	/* write H fine-scaling (chrominance)
939cb7a01acSMauro Carvalho Chehab 	 * must be lum/2, so i'll just bitshift :) */
940cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
941cb7a01acSMauro Carvalho Chehab 				(u8) ((HFSC >> 1) & 0xff));
942cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
943cb7a01acSMauro Carvalho Chehab 				(u8) ((HFSC >> 9) & 0xff));
944cb7a01acSMauro Carvalho Chehab 
945cb7a01acSMauro Carvalho Chehab 	VSCY = (int)((1024 * Vsrc) / height);
946cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
947cb7a01acSMauro Carvalho Chehab 
948cb7a01acSMauro Carvalho Chehab 	/* Correct Contrast and Luminance */
949cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
950cb7a01acSMauro Carvalho Chehab 					(u8) (64 * 1024 / VSCY));
951cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
952cb7a01acSMauro Carvalho Chehab 					(u8) (64 * 1024 / VSCY));
953cb7a01acSMauro Carvalho Chehab 
954cb7a01acSMauro Carvalho Chehab 		/* write V fine-scaling (luminance) */
955cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
956cb7a01acSMauro Carvalho Chehab 					(u8) (VSCY & 0xff));
957cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
958cb7a01acSMauro Carvalho Chehab 					(u8) ((VSCY >> 8) & 0xff));
959cb7a01acSMauro Carvalho Chehab 		/* write V fine-scaling (chrominance) */
960cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
961cb7a01acSMauro Carvalho Chehab 					(u8) (VSCY & 0xff));
962cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
963cb7a01acSMauro Carvalho Chehab 					(u8) ((VSCY >> 8) & 0xff));
964cb7a01acSMauro Carvalho Chehab 
965cb7a01acSMauro Carvalho Chehab 	saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
966cb7a01acSMauro Carvalho Chehab 
967cb7a01acSMauro Carvalho Chehab 	/* Activates task "B" */
968cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_80_GLOBAL_CNTL_1,
969cb7a01acSMauro Carvalho Chehab 				saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
970cb7a01acSMauro Carvalho Chehab 
971cb7a01acSMauro Carvalho Chehab 	return 0;
972cb7a01acSMauro Carvalho Chehab }
973cb7a01acSMauro Carvalho Chehab 
974cb7a01acSMauro Carvalho Chehab static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
975cb7a01acSMauro Carvalho Chehab {
976cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
977cb7a01acSMauro Carvalho Chehab 
978cb7a01acSMauro Carvalho Chehab 	/* Prevent unnecessary standard changes. During a standard
979cb7a01acSMauro Carvalho Chehab 	   change the I-Port is temporarily disabled. Any devices
980cb7a01acSMauro Carvalho Chehab 	   reading from that port can get confused.
981cb7a01acSMauro Carvalho Chehab 	   Note that s_std is also used to switch from
982cb7a01acSMauro Carvalho Chehab 	   radio to TV mode, so if a s_std is broadcast to
983cb7a01acSMauro Carvalho Chehab 	   all I2C devices then you do not want to have an unwanted
984cb7a01acSMauro Carvalho Chehab 	   side-effect here. */
985cb7a01acSMauro Carvalho Chehab 	if (std == state->std)
986cb7a01acSMauro Carvalho Chehab 		return;
987cb7a01acSMauro Carvalho Chehab 
988cb7a01acSMauro Carvalho Chehab 	state->std = std;
989cb7a01acSMauro Carvalho Chehab 
990cb7a01acSMauro Carvalho Chehab 	// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
991cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_525_60) {
992cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
9938b77dfddSJon Arne Jørgensen 		if (state->ident == GM7113C) {
9948b77dfddSJon Arne Jørgensen 			u8 reg = saa711x_read(sd, R_08_SYNC_CNTL);
9958b77dfddSJon Arne Jørgensen 			reg &= ~(SAA7113_R_08_FSEL | SAA7113_R_08_AUFD);
9968b77dfddSJon Arne Jørgensen 			reg |= SAA7113_R_08_FSEL;
9978b77dfddSJon Arne Jørgensen 			saa711x_write(sd, R_08_SYNC_CNTL, reg);
9988b77dfddSJon Arne Jørgensen 		} else {
999cb7a01acSMauro Carvalho Chehab 			saa711x_writeregs(sd, saa7115_cfg_60hz_video);
10008b77dfddSJon Arne Jørgensen 		}
1001cb7a01acSMauro Carvalho Chehab 		saa711x_set_size(sd, 720, 480);
1002cb7a01acSMauro Carvalho Chehab 	} else {
1003cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
10048b77dfddSJon Arne Jørgensen 		if (state->ident == GM7113C) {
10058b77dfddSJon Arne Jørgensen 			u8 reg = saa711x_read(sd, R_08_SYNC_CNTL);
10068b77dfddSJon Arne Jørgensen 			reg &= ~(SAA7113_R_08_FSEL | SAA7113_R_08_AUFD);
10078b77dfddSJon Arne Jørgensen 			saa711x_write(sd, R_08_SYNC_CNTL, reg);
10088b77dfddSJon Arne Jørgensen 		} else {
1009cb7a01acSMauro Carvalho Chehab 			saa711x_writeregs(sd, saa7115_cfg_50hz_video);
10108b77dfddSJon Arne Jørgensen 		}
1011cb7a01acSMauro Carvalho Chehab 		saa711x_set_size(sd, 720, 576);
1012cb7a01acSMauro Carvalho Chehab 	}
1013cb7a01acSMauro Carvalho Chehab 
1014cb7a01acSMauro Carvalho Chehab 	/* Register 0E - Bits D6-D4 on NO-AUTO mode
1015cb7a01acSMauro Carvalho Chehab 		(SAA7111 and SAA7113 doesn't have auto mode)
1016cb7a01acSMauro Carvalho Chehab 	    50 Hz / 625 lines           60 Hz / 525 lines
1017cb7a01acSMauro Carvalho Chehab 	000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)
1018cb7a01acSMauro Carvalho Chehab 	001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)
1019cb7a01acSMauro Carvalho Chehab 	010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
1020cb7a01acSMauro Carvalho Chehab 	011 NTSC N (3.58MHz)            PAL M (3.58MHz)
1021cb7a01acSMauro Carvalho Chehab 	100 reserved                    NTSC-Japan (3.58MHz)
1022cb7a01acSMauro Carvalho Chehab 	*/
1023e1277110SHans Verkuil 	if (state->ident <= SAA7113 ||
1024e1277110SHans Verkuil 	    state->ident == GM7113C) {
1025cb7a01acSMauro Carvalho Chehab 		u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
1026cb7a01acSMauro Carvalho Chehab 
1027cb7a01acSMauro Carvalho Chehab 		if (std == V4L2_STD_PAL_M) {
1028cb7a01acSMauro Carvalho Chehab 			reg |= 0x30;
1029cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_PAL_Nc) {
1030cb7a01acSMauro Carvalho Chehab 			reg |= 0x20;
1031cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_PAL_60) {
1032cb7a01acSMauro Carvalho Chehab 			reg |= 0x10;
1033cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_NTSC_M_JP) {
1034cb7a01acSMauro Carvalho Chehab 			reg |= 0x40;
1035cb7a01acSMauro Carvalho Chehab 		} else if (std & V4L2_STD_SECAM) {
1036cb7a01acSMauro Carvalho Chehab 			reg |= 0x50;
1037cb7a01acSMauro Carvalho Chehab 		}
1038cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
1039cb7a01acSMauro Carvalho Chehab 	} else {
1040cb7a01acSMauro Carvalho Chehab 		/* restart task B if needed */
1041cb7a01acSMauro Carvalho Chehab 		int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
1042cb7a01acSMauro Carvalho Chehab 
1043e1277110SHans Verkuil 		if (taskb && state->ident == SAA7114)
1044cb7a01acSMauro Carvalho Chehab 			saa711x_writeregs(sd, saa7115_cfg_vbi_on);
1045cb7a01acSMauro Carvalho Chehab 
1046cb7a01acSMauro Carvalho Chehab 		/* switch audio mode too! */
1047cb7a01acSMauro Carvalho Chehab 		saa711x_s_clock_freq(sd, state->audclk_freq);
1048cb7a01acSMauro Carvalho Chehab 	}
1049cb7a01acSMauro Carvalho Chehab }
1050cb7a01acSMauro Carvalho Chehab 
1051cb7a01acSMauro Carvalho Chehab /* setup the sliced VBI lcr registers according to the sliced VBI format */
1052cb7a01acSMauro Carvalho Chehab static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
1053cb7a01acSMauro Carvalho Chehab {
1054cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1055cb7a01acSMauro Carvalho Chehab 	int is_50hz = (state->std & V4L2_STD_625_50);
1056cb7a01acSMauro Carvalho Chehab 	u8 lcr[24];
1057cb7a01acSMauro Carvalho Chehab 	int i, x;
1058cb7a01acSMauro Carvalho Chehab 
1059cb7a01acSMauro Carvalho Chehab #if 1
1060cb7a01acSMauro Carvalho Chehab 	/* saa7113/7114/7118 VBI support are experimental */
1061cb7a01acSMauro Carvalho Chehab 	if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
1062cb7a01acSMauro Carvalho Chehab 		return;
1063cb7a01acSMauro Carvalho Chehab 
1064cb7a01acSMauro Carvalho Chehab #else
1065cb7a01acSMauro Carvalho Chehab 	/* SAA7113 and SAA7118 also should support VBI - Need testing */
1066e1277110SHans Verkuil 	if (state->ident != SAA7115)
1067cb7a01acSMauro Carvalho Chehab 		return;
1068cb7a01acSMauro Carvalho Chehab #endif
1069cb7a01acSMauro Carvalho Chehab 
1070cb7a01acSMauro Carvalho Chehab 	for (i = 0; i <= 23; i++)
1071cb7a01acSMauro Carvalho Chehab 		lcr[i] = 0xff;
1072cb7a01acSMauro Carvalho Chehab 
1073cb7a01acSMauro Carvalho Chehab 	if (fmt == NULL) {
1074cb7a01acSMauro Carvalho Chehab 		/* raw VBI */
1075cb7a01acSMauro Carvalho Chehab 		if (is_50hz)
1076cb7a01acSMauro Carvalho Chehab 			for (i = 6; i <= 23; i++)
1077cb7a01acSMauro Carvalho Chehab 				lcr[i] = 0xdd;
1078cb7a01acSMauro Carvalho Chehab 		else
1079cb7a01acSMauro Carvalho Chehab 			for (i = 10; i <= 21; i++)
1080cb7a01acSMauro Carvalho Chehab 				lcr[i] = 0xdd;
1081cb7a01acSMauro Carvalho Chehab 	} else {
1082cb7a01acSMauro Carvalho Chehab 		/* sliced VBI */
1083cb7a01acSMauro Carvalho Chehab 		/* first clear lines that cannot be captured */
1084cb7a01acSMauro Carvalho Chehab 		if (is_50hz) {
1085cb7a01acSMauro Carvalho Chehab 			for (i = 0; i <= 5; i++)
1086cb7a01acSMauro Carvalho Chehab 				fmt->service_lines[0][i] =
1087cb7a01acSMauro Carvalho Chehab 					fmt->service_lines[1][i] = 0;
1088cb7a01acSMauro Carvalho Chehab 		}
1089cb7a01acSMauro Carvalho Chehab 		else {
1090cb7a01acSMauro Carvalho Chehab 			for (i = 0; i <= 9; i++)
1091cb7a01acSMauro Carvalho Chehab 				fmt->service_lines[0][i] =
1092cb7a01acSMauro Carvalho Chehab 					fmt->service_lines[1][i] = 0;
1093cb7a01acSMauro Carvalho Chehab 			for (i = 22; i <= 23; i++)
1094cb7a01acSMauro Carvalho Chehab 				fmt->service_lines[0][i] =
1095cb7a01acSMauro Carvalho Chehab 					fmt->service_lines[1][i] = 0;
1096cb7a01acSMauro Carvalho Chehab 		}
1097cb7a01acSMauro Carvalho Chehab 
1098cb7a01acSMauro Carvalho Chehab 		/* Now set the lcr values according to the specified service */
1099cb7a01acSMauro Carvalho Chehab 		for (i = 6; i <= 23; i++) {
1100cb7a01acSMauro Carvalho Chehab 			lcr[i] = 0;
1101cb7a01acSMauro Carvalho Chehab 			for (x = 0; x <= 1; x++) {
1102cb7a01acSMauro Carvalho Chehab 				switch (fmt->service_lines[1-x][i]) {
1103cb7a01acSMauro Carvalho Chehab 					case 0:
1104cb7a01acSMauro Carvalho Chehab 						lcr[i] |= 0xf << (4 * x);
1105cb7a01acSMauro Carvalho Chehab 						break;
1106cb7a01acSMauro Carvalho Chehab 					case V4L2_SLICED_TELETEXT_B:
1107cb7a01acSMauro Carvalho Chehab 						lcr[i] |= 1 << (4 * x);
1108cb7a01acSMauro Carvalho Chehab 						break;
1109cb7a01acSMauro Carvalho Chehab 					case V4L2_SLICED_CAPTION_525:
1110cb7a01acSMauro Carvalho Chehab 						lcr[i] |= 4 << (4 * x);
1111cb7a01acSMauro Carvalho Chehab 						break;
1112cb7a01acSMauro Carvalho Chehab 					case V4L2_SLICED_WSS_625:
1113cb7a01acSMauro Carvalho Chehab 						lcr[i] |= 5 << (4 * x);
1114cb7a01acSMauro Carvalho Chehab 						break;
1115cb7a01acSMauro Carvalho Chehab 					case V4L2_SLICED_VPS:
1116cb7a01acSMauro Carvalho Chehab 						lcr[i] |= 7 << (4 * x);
1117cb7a01acSMauro Carvalho Chehab 						break;
1118cb7a01acSMauro Carvalho Chehab 				}
1119cb7a01acSMauro Carvalho Chehab 			}
1120cb7a01acSMauro Carvalho Chehab 		}
1121cb7a01acSMauro Carvalho Chehab 	}
1122cb7a01acSMauro Carvalho Chehab 
1123cb7a01acSMauro Carvalho Chehab 	/* write the lcr registers */
1124cb7a01acSMauro Carvalho Chehab 	for (i = 2; i <= 23; i++) {
1125cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
1126cb7a01acSMauro Carvalho Chehab 	}
1127cb7a01acSMauro Carvalho Chehab 
1128cb7a01acSMauro Carvalho Chehab 	/* enable/disable raw VBI capturing */
1129cb7a01acSMauro Carvalho Chehab 	saa711x_writeregs(sd, fmt == NULL ?
1130cb7a01acSMauro Carvalho Chehab 				saa7115_cfg_vbi_on :
1131cb7a01acSMauro Carvalho Chehab 				saa7115_cfg_vbi_off);
1132cb7a01acSMauro Carvalho Chehab }
1133cb7a01acSMauro Carvalho Chehab 
1134cb7a01acSMauro Carvalho Chehab static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *sliced)
1135cb7a01acSMauro Carvalho Chehab {
1136cb7a01acSMauro Carvalho Chehab 	static u16 lcr2vbi[] = {
1137cb7a01acSMauro Carvalho Chehab 		0, V4L2_SLICED_TELETEXT_B, 0,	/* 1 */
1138cb7a01acSMauro Carvalho Chehab 		0, V4L2_SLICED_CAPTION_525,	/* 4 */
1139cb7a01acSMauro Carvalho Chehab 		V4L2_SLICED_WSS_625, 0,		/* 5 */
1140cb7a01acSMauro Carvalho Chehab 		V4L2_SLICED_VPS, 0, 0, 0, 0,	/* 7 */
1141cb7a01acSMauro Carvalho Chehab 		0, 0, 0, 0
1142cb7a01acSMauro Carvalho Chehab 	};
1143cb7a01acSMauro Carvalho Chehab 	int i;
1144cb7a01acSMauro Carvalho Chehab 
114530634e8eSHans Verkuil 	memset(sliced->service_lines, 0, sizeof(sliced->service_lines));
114630634e8eSHans Verkuil 	sliced->service_set = 0;
1147cb7a01acSMauro Carvalho Chehab 	/* done if using raw VBI */
1148cb7a01acSMauro Carvalho Chehab 	if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
1149cb7a01acSMauro Carvalho Chehab 		return 0;
1150cb7a01acSMauro Carvalho Chehab 	for (i = 2; i <= 23; i++) {
1151cb7a01acSMauro Carvalho Chehab 		u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
1152cb7a01acSMauro Carvalho Chehab 
1153cb7a01acSMauro Carvalho Chehab 		sliced->service_lines[0][i] = lcr2vbi[v >> 4];
1154cb7a01acSMauro Carvalho Chehab 		sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
1155cb7a01acSMauro Carvalho Chehab 		sliced->service_set |=
1156cb7a01acSMauro Carvalho Chehab 			sliced->service_lines[0][i] | sliced->service_lines[1][i];
1157cb7a01acSMauro Carvalho Chehab 	}
1158cb7a01acSMauro Carvalho Chehab 	return 0;
1159cb7a01acSMauro Carvalho Chehab }
1160cb7a01acSMauro Carvalho Chehab 
1161cb7a01acSMauro Carvalho Chehab static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
1162cb7a01acSMauro Carvalho Chehab {
1163cb7a01acSMauro Carvalho Chehab 	saa711x_set_lcr(sd, NULL);
1164cb7a01acSMauro Carvalho Chehab 	return 0;
1165cb7a01acSMauro Carvalho Chehab }
1166cb7a01acSMauro Carvalho Chehab 
1167cb7a01acSMauro Carvalho Chehab static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
1168cb7a01acSMauro Carvalho Chehab {
1169cb7a01acSMauro Carvalho Chehab 	saa711x_set_lcr(sd, fmt);
1170cb7a01acSMauro Carvalho Chehab 	return 0;
1171cb7a01acSMauro Carvalho Chehab }
1172cb7a01acSMauro Carvalho Chehab 
1173cb7a01acSMauro Carvalho Chehab static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
1174cb7a01acSMauro Carvalho Chehab {
1175cb7a01acSMauro Carvalho Chehab 	if (fmt->code != V4L2_MBUS_FMT_FIXED)
1176cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1177cb7a01acSMauro Carvalho Chehab 	fmt->field = V4L2_FIELD_INTERLACED;
1178cb7a01acSMauro Carvalho Chehab 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1179cb7a01acSMauro Carvalho Chehab 	return saa711x_set_size(sd, fmt->width, fmt->height);
1180cb7a01acSMauro Carvalho Chehab }
1181cb7a01acSMauro Carvalho Chehab 
1182cb7a01acSMauro Carvalho Chehab /* Decode the sliced VBI data stream as created by the saa7115.
1183cb7a01acSMauro Carvalho Chehab    The format is described in the saa7115 datasheet in Tables 25 and 26
1184cb7a01acSMauro Carvalho Chehab    and in Figure 33.
1185cb7a01acSMauro Carvalho Chehab    The current implementation uses SAV/EAV codes and not the ancillary data
1186cb7a01acSMauro Carvalho Chehab    headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
1187cb7a01acSMauro Carvalho Chehab    code. */
1188cb7a01acSMauro Carvalho Chehab static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
1189cb7a01acSMauro Carvalho Chehab {
1190cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1191cb7a01acSMauro Carvalho Chehab 	static const char vbi_no_data_pattern[] = {
1192cb7a01acSMauro Carvalho Chehab 		0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
1193cb7a01acSMauro Carvalho Chehab 	};
1194cb7a01acSMauro Carvalho Chehab 	u8 *p = vbi->p;
1195cb7a01acSMauro Carvalho Chehab 	u32 wss;
1196cb7a01acSMauro Carvalho Chehab 	int id1, id2;   /* the ID1 and ID2 bytes from the internal header */
1197cb7a01acSMauro Carvalho Chehab 
1198cb7a01acSMauro Carvalho Chehab 	vbi->type = 0;  /* mark result as a failure */
1199cb7a01acSMauro Carvalho Chehab 	id1 = p[2];
1200cb7a01acSMauro Carvalho Chehab 	id2 = p[3];
1201cb7a01acSMauro Carvalho Chehab 	/* Note: the field bit is inverted for 60 Hz video */
1202cb7a01acSMauro Carvalho Chehab 	if (state->std & V4L2_STD_525_60)
1203cb7a01acSMauro Carvalho Chehab 		id1 ^= 0x40;
1204cb7a01acSMauro Carvalho Chehab 
1205cb7a01acSMauro Carvalho Chehab 	/* Skip internal header, p now points to the start of the payload */
1206cb7a01acSMauro Carvalho Chehab 	p += 4;
1207cb7a01acSMauro Carvalho Chehab 	vbi->p = p;
1208cb7a01acSMauro Carvalho Chehab 
1209cb7a01acSMauro Carvalho Chehab 	/* calculate field and line number of the VBI packet (1-23) */
1210cb7a01acSMauro Carvalho Chehab 	vbi->is_second_field = ((id1 & 0x40) != 0);
1211cb7a01acSMauro Carvalho Chehab 	vbi->line = (id1 & 0x3f) << 3;
1212cb7a01acSMauro Carvalho Chehab 	vbi->line |= (id2 & 0x70) >> 4;
1213cb7a01acSMauro Carvalho Chehab 
1214cb7a01acSMauro Carvalho Chehab 	/* Obtain data type */
1215cb7a01acSMauro Carvalho Chehab 	id2 &= 0xf;
1216cb7a01acSMauro Carvalho Chehab 
1217cb7a01acSMauro Carvalho Chehab 	/* If the VBI slicer does not detect any signal it will fill up
1218cb7a01acSMauro Carvalho Chehab 	   the payload buffer with 0xa0 bytes. */
1219cb7a01acSMauro Carvalho Chehab 	if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
1220cb7a01acSMauro Carvalho Chehab 		return 0;
1221cb7a01acSMauro Carvalho Chehab 
1222cb7a01acSMauro Carvalho Chehab 	/* decode payloads */
1223cb7a01acSMauro Carvalho Chehab 	switch (id2) {
1224cb7a01acSMauro Carvalho Chehab 	case 1:
1225cb7a01acSMauro Carvalho Chehab 		vbi->type = V4L2_SLICED_TELETEXT_B;
1226cb7a01acSMauro Carvalho Chehab 		break;
1227cb7a01acSMauro Carvalho Chehab 	case 4:
1228cb7a01acSMauro Carvalho Chehab 		if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
1229cb7a01acSMauro Carvalho Chehab 			return 0;
1230cb7a01acSMauro Carvalho Chehab 		vbi->type = V4L2_SLICED_CAPTION_525;
1231cb7a01acSMauro Carvalho Chehab 		break;
1232cb7a01acSMauro Carvalho Chehab 	case 5:
1233cb7a01acSMauro Carvalho Chehab 		wss = saa711x_decode_wss(p);
1234cb7a01acSMauro Carvalho Chehab 		if (wss == -1)
1235cb7a01acSMauro Carvalho Chehab 			return 0;
1236cb7a01acSMauro Carvalho Chehab 		p[0] = wss & 0xff;
1237cb7a01acSMauro Carvalho Chehab 		p[1] = wss >> 8;
1238cb7a01acSMauro Carvalho Chehab 		vbi->type = V4L2_SLICED_WSS_625;
1239cb7a01acSMauro Carvalho Chehab 		break;
1240cb7a01acSMauro Carvalho Chehab 	case 7:
1241cb7a01acSMauro Carvalho Chehab 		if (saa711x_decode_vps(p, p) != 0)
1242cb7a01acSMauro Carvalho Chehab 			return 0;
1243cb7a01acSMauro Carvalho Chehab 		vbi->type = V4L2_SLICED_VPS;
1244cb7a01acSMauro Carvalho Chehab 		break;
1245cb7a01acSMauro Carvalho Chehab 	default:
1246cb7a01acSMauro Carvalho Chehab 		break;
1247cb7a01acSMauro Carvalho Chehab 	}
1248cb7a01acSMauro Carvalho Chehab 	return 0;
1249cb7a01acSMauro Carvalho Chehab }
1250cb7a01acSMauro Carvalho Chehab 
1251cb7a01acSMauro Carvalho Chehab /* ============ SAA7115 AUDIO settings (end) ============= */
1252cb7a01acSMauro Carvalho Chehab 
1253cb7a01acSMauro Carvalho Chehab static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1254cb7a01acSMauro Carvalho Chehab {
1255cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1256cb7a01acSMauro Carvalho Chehab 	int status;
1257cb7a01acSMauro Carvalho Chehab 
1258cb7a01acSMauro Carvalho Chehab 	if (state->radio)
1259cb7a01acSMauro Carvalho Chehab 		return 0;
1260cb7a01acSMauro Carvalho Chehab 	status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1261cb7a01acSMauro Carvalho Chehab 
1262cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
1263cb7a01acSMauro Carvalho Chehab 	vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
1264cb7a01acSMauro Carvalho Chehab 	return 0;
1265cb7a01acSMauro Carvalho Chehab }
1266cb7a01acSMauro Carvalho Chehab 
1267cb7a01acSMauro Carvalho Chehab static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
1268cb7a01acSMauro Carvalho Chehab {
1269cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1270cb7a01acSMauro Carvalho Chehab 
1271cb7a01acSMauro Carvalho Chehab 	state->radio = 0;
1272cb7a01acSMauro Carvalho Chehab 	saa711x_set_v4lstd(sd, std);
1273cb7a01acSMauro Carvalho Chehab 	return 0;
1274cb7a01acSMauro Carvalho Chehab }
1275cb7a01acSMauro Carvalho Chehab 
1276cb7a01acSMauro Carvalho Chehab static int saa711x_s_radio(struct v4l2_subdev *sd)
1277cb7a01acSMauro Carvalho Chehab {
1278cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1279cb7a01acSMauro Carvalho Chehab 
1280cb7a01acSMauro Carvalho Chehab 	state->radio = 1;
1281cb7a01acSMauro Carvalho Chehab 	return 0;
1282cb7a01acSMauro Carvalho Chehab }
1283cb7a01acSMauro Carvalho Chehab 
1284cb7a01acSMauro Carvalho Chehab static int saa711x_s_routing(struct v4l2_subdev *sd,
1285cb7a01acSMauro Carvalho Chehab 			     u32 input, u32 output, u32 config)
1286cb7a01acSMauro Carvalho Chehab {
1287cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1288e1277110SHans Verkuil 	u8 mask = (state->ident <= SAA7111A) ? 0xf8 : 0xf0;
1289cb7a01acSMauro Carvalho Chehab 
1290cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n",
1291cb7a01acSMauro Carvalho Chehab 		input, output);
1292cb7a01acSMauro Carvalho Chehab 
1293cb7a01acSMauro Carvalho Chehab 	/* saa7111/3 does not have these inputs */
1294e1277110SHans Verkuil 	if ((state->ident <= SAA7113 ||
1295e1277110SHans Verkuil 	     state->ident == GM7113C) &&
1296cb7a01acSMauro Carvalho Chehab 	    (input == SAA7115_COMPOSITE4 ||
1297cb7a01acSMauro Carvalho Chehab 	     input == SAA7115_COMPOSITE5)) {
1298cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1299cb7a01acSMauro Carvalho Chehab 	}
1300cb7a01acSMauro Carvalho Chehab 	if (input > SAA7115_SVIDEO3)
1301cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1302cb7a01acSMauro Carvalho Chehab 	if (state->input == input && state->output == output)
1303cb7a01acSMauro Carvalho Chehab 		return 0;
1304cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
1305cb7a01acSMauro Carvalho Chehab 		(input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
1306cb7a01acSMauro Carvalho Chehab 		(output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
1307cb7a01acSMauro Carvalho Chehab 	state->input = input;
1308cb7a01acSMauro Carvalho Chehab 
1309cb7a01acSMauro Carvalho Chehab 	/* saa7111 has slightly different input numbering */
1310e1277110SHans Verkuil 	if (state->ident <= SAA7111A) {
1311cb7a01acSMauro Carvalho Chehab 		if (input >= SAA7115_COMPOSITE4)
1312cb7a01acSMauro Carvalho Chehab 			input -= 2;
1313cb7a01acSMauro Carvalho Chehab 		/* saa7111 specific */
1314cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_10_CHROMA_CNTL_2,
1315cb7a01acSMauro Carvalho Chehab 				(saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
1316cb7a01acSMauro Carvalho Chehab 				((output & 0xc0) ^ 0x40));
1317cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
1318cb7a01acSMauro Carvalho Chehab 				(saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
1319cb7a01acSMauro Carvalho Chehab 				((output & 2) ? 0x0a : 0));
1320cb7a01acSMauro Carvalho Chehab 	}
1321cb7a01acSMauro Carvalho Chehab 
1322cb7a01acSMauro Carvalho Chehab 	/* select mode */
1323cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_02_INPUT_CNTL_1,
1324cb7a01acSMauro Carvalho Chehab 		      (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
1325cb7a01acSMauro Carvalho Chehab 		       input);
1326cb7a01acSMauro Carvalho Chehab 
1327cb7a01acSMauro Carvalho Chehab 	/* bypass chrominance trap for S-Video modes */
1328cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_09_LUMA_CNTL,
1329cb7a01acSMauro Carvalho Chehab 			(saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
1330cb7a01acSMauro Carvalho Chehab 			(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
1331cb7a01acSMauro Carvalho Chehab 
1332cb7a01acSMauro Carvalho Chehab 	state->output = output;
1333e1277110SHans Verkuil 	if (state->ident == SAA7114 ||
1334e1277110SHans Verkuil 			state->ident == SAA7115) {
1335cb7a01acSMauro Carvalho Chehab 		saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
1336cb7a01acSMauro Carvalho Chehab 				(saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
1337cb7a01acSMauro Carvalho Chehab 				(state->output & 0x01));
1338cb7a01acSMauro Carvalho Chehab 	}
1339e1277110SHans Verkuil 	if (state->ident > SAA7111A) {
1340a0fc5886SHans Verkuil 		if (config & SAA7115_IDQ_IS_DEFAULT)
1341a0fc5886SHans Verkuil 			saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20);
1342a0fc5886SHans Verkuil 		else
1343a0fc5886SHans Verkuil 			saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x21);
1344a0fc5886SHans Verkuil 	}
1345cb7a01acSMauro Carvalho Chehab 	return 0;
1346cb7a01acSMauro Carvalho Chehab }
1347cb7a01acSMauro Carvalho Chehab 
1348cb7a01acSMauro Carvalho Chehab static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
1349cb7a01acSMauro Carvalho Chehab {
1350cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1351cb7a01acSMauro Carvalho Chehab 
1352e1277110SHans Verkuil 	if (state->ident > SAA7111A)
1353cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1354cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
1355cb7a01acSMauro Carvalho Chehab 		(val ? 0x80 : 0));
1356cb7a01acSMauro Carvalho Chehab 	return 0;
1357cb7a01acSMauro Carvalho Chehab }
1358cb7a01acSMauro Carvalho Chehab 
1359cb7a01acSMauro Carvalho Chehab static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
1360cb7a01acSMauro Carvalho Chehab {
1361cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1362cb7a01acSMauro Carvalho Chehab 
1363cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "%s output\n",
1364cb7a01acSMauro Carvalho Chehab 			enable ? "enable" : "disable");
1365cb7a01acSMauro Carvalho Chehab 
1366cb7a01acSMauro Carvalho Chehab 	if (state->enable == enable)
1367cb7a01acSMauro Carvalho Chehab 		return 0;
1368cb7a01acSMauro Carvalho Chehab 	state->enable = enable;
1369cb7a01acSMauro Carvalho Chehab 	if (!saa711x_has_reg(state->ident, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED))
1370cb7a01acSMauro Carvalho Chehab 		return 0;
1371cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, state->enable);
1372cb7a01acSMauro Carvalho Chehab 	return 0;
1373cb7a01acSMauro Carvalho Chehab }
1374cb7a01acSMauro Carvalho Chehab 
1375cb7a01acSMauro Carvalho Chehab static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags)
1376cb7a01acSMauro Carvalho Chehab {
1377cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1378cb7a01acSMauro Carvalho Chehab 
1379cb7a01acSMauro Carvalho Chehab 	if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ)
1380cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1381cb7a01acSMauro Carvalho Chehab 	state->crystal_freq = freq;
13821589037fSHans Verkuil 	state->double_asclk = flags & SAA7115_FREQ_FL_DOUBLE_ASCLK;
1383cb7a01acSMauro Carvalho Chehab 	state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
13841589037fSHans Verkuil 	state->ucgc = flags & SAA7115_FREQ_FL_UCGC;
13851589037fSHans Verkuil 	state->apll = flags & SAA7115_FREQ_FL_APLL;
1386cb7a01acSMauro Carvalho Chehab 	saa711x_s_clock_freq(sd, state->audclk_freq);
1387cb7a01acSMauro Carvalho Chehab 	return 0;
1388cb7a01acSMauro Carvalho Chehab }
1389cb7a01acSMauro Carvalho Chehab 
1390cb7a01acSMauro Carvalho Chehab static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
1391cb7a01acSMauro Carvalho Chehab {
1392cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "decoder RESET\n");
1393cb7a01acSMauro Carvalho Chehab 	saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
1394cb7a01acSMauro Carvalho Chehab 	return 0;
1395cb7a01acSMauro Carvalho Chehab }
1396cb7a01acSMauro Carvalho Chehab 
1397cb7a01acSMauro Carvalho Chehab static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
1398cb7a01acSMauro Carvalho Chehab {
1399cb7a01acSMauro Carvalho Chehab 	/* Note: the internal field ID is inverted for NTSC,
1400cb7a01acSMauro Carvalho Chehab 	   so data->field 0 maps to the saa7115 even field,
1401cb7a01acSMauro Carvalho Chehab 	   whereas for PAL it maps to the saa7115 odd field. */
1402cb7a01acSMauro Carvalho Chehab 	switch (data->id) {
1403cb7a01acSMauro Carvalho Chehab 	case V4L2_SLICED_WSS_625:
1404cb7a01acSMauro Carvalho Chehab 		if (saa711x_read(sd, 0x6b) & 0xc0)
1405cb7a01acSMauro Carvalho Chehab 			return -EIO;
1406cb7a01acSMauro Carvalho Chehab 		data->data[0] = saa711x_read(sd, 0x6c);
1407cb7a01acSMauro Carvalho Chehab 		data->data[1] = saa711x_read(sd, 0x6d);
1408cb7a01acSMauro Carvalho Chehab 		return 0;
1409cb7a01acSMauro Carvalho Chehab 	case V4L2_SLICED_CAPTION_525:
1410cb7a01acSMauro Carvalho Chehab 		if (data->field == 0) {
1411cb7a01acSMauro Carvalho Chehab 			/* CC */
1412cb7a01acSMauro Carvalho Chehab 			if (saa711x_read(sd, 0x66) & 0x30)
1413cb7a01acSMauro Carvalho Chehab 				return -EIO;
1414cb7a01acSMauro Carvalho Chehab 			data->data[0] = saa711x_read(sd, 0x69);
1415cb7a01acSMauro Carvalho Chehab 			data->data[1] = saa711x_read(sd, 0x6a);
1416cb7a01acSMauro Carvalho Chehab 			return 0;
1417cb7a01acSMauro Carvalho Chehab 		}
1418cb7a01acSMauro Carvalho Chehab 		/* XDS */
1419cb7a01acSMauro Carvalho Chehab 		if (saa711x_read(sd, 0x66) & 0xc0)
1420cb7a01acSMauro Carvalho Chehab 			return -EIO;
1421cb7a01acSMauro Carvalho Chehab 		data->data[0] = saa711x_read(sd, 0x67);
1422cb7a01acSMauro Carvalho Chehab 		data->data[1] = saa711x_read(sd, 0x68);
1423cb7a01acSMauro Carvalho Chehab 		return 0;
1424cb7a01acSMauro Carvalho Chehab 	default:
1425cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1426cb7a01acSMauro Carvalho Chehab 	}
1427cb7a01acSMauro Carvalho Chehab }
1428cb7a01acSMauro Carvalho Chehab 
1429cb7a01acSMauro Carvalho Chehab static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
1430cb7a01acSMauro Carvalho Chehab {
1431cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1432cb7a01acSMauro Carvalho Chehab 	int reg1f, reg1e;
1433cb7a01acSMauro Carvalho Chehab 
1434cb7a01acSMauro Carvalho Chehab 	/*
1435cb7a01acSMauro Carvalho Chehab 	 * The V4L2 core already initializes std with all supported
1436cb7a01acSMauro Carvalho Chehab 	 * Standards. All driver needs to do is to mask it, to remove
1437cb7a01acSMauro Carvalho Chehab 	 * standards that don't apply from the mask
1438cb7a01acSMauro Carvalho Chehab 	 */
1439cb7a01acSMauro Carvalho Chehab 
1440cb7a01acSMauro Carvalho Chehab 	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1441cb7a01acSMauro Carvalho Chehab 
1442e1277110SHans Verkuil 	if (state->ident == SAA7115) {
1443cb7a01acSMauro Carvalho Chehab 		reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1444cb7a01acSMauro Carvalho Chehab 
1445c875dee5SHans Verkuil 		v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
1446c875dee5SHans Verkuil 
1447cb7a01acSMauro Carvalho Chehab 		switch (reg1e & 0x03) {
1448cb7a01acSMauro Carvalho Chehab 		case 1:
1449cb7a01acSMauro Carvalho Chehab 			*std &= V4L2_STD_NTSC;
1450cb7a01acSMauro Carvalho Chehab 			break;
1451cb7a01acSMauro Carvalho Chehab 		case 2:
1452cb7a01acSMauro Carvalho Chehab 			/*
1453cb7a01acSMauro Carvalho Chehab 			 * V4L2_STD_PAL just cover the european PAL standards.
1454cb7a01acSMauro Carvalho Chehab 			 * This is wrong, as the device could also be using an
1455cb7a01acSMauro Carvalho Chehab 			 * other PAL standard.
1456cb7a01acSMauro Carvalho Chehab 			 */
1457cb7a01acSMauro Carvalho Chehab 			*std &= V4L2_STD_PAL   | V4L2_STD_PAL_N  | V4L2_STD_PAL_Nc |
1458cb7a01acSMauro Carvalho Chehab 				V4L2_STD_PAL_M | V4L2_STD_PAL_60;
1459cb7a01acSMauro Carvalho Chehab 			break;
1460cb7a01acSMauro Carvalho Chehab 		case 3:
1461cb7a01acSMauro Carvalho Chehab 			*std &= V4L2_STD_SECAM;
1462cb7a01acSMauro Carvalho Chehab 			break;
1463cb7a01acSMauro Carvalho Chehab 		default:
1464af1f7284SHans Verkuil 			*std = V4L2_STD_UNKNOWN;
1465cb7a01acSMauro Carvalho Chehab 			/* Can't detect anything */
1466cb7a01acSMauro Carvalho Chehab 			break;
1467cb7a01acSMauro Carvalho Chehab 		}
1468c875dee5SHans Verkuil 	}
1469cb7a01acSMauro Carvalho Chehab 
1470c875dee5SHans Verkuil 	v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
1471c875dee5SHans Verkuil 
1472c875dee5SHans Verkuil 	/* horizontal/vertical not locked */
1473af1f7284SHans Verkuil 	if (reg1f & 0x40) {
1474af1f7284SHans Verkuil 		*std = V4L2_STD_UNKNOWN;
1475c875dee5SHans Verkuil 		goto ret;
1476af1f7284SHans Verkuil 	}
1477c875dee5SHans Verkuil 
1478c875dee5SHans Verkuil 	if (reg1f & 0x20)
1479c875dee5SHans Verkuil 		*std &= V4L2_STD_525_60;
1480c875dee5SHans Verkuil 	else
1481c875dee5SHans Verkuil 		*std &= V4L2_STD_625_50;
1482cb7a01acSMauro Carvalho Chehab 
1483cb7a01acSMauro Carvalho Chehab ret:
1484cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std);
1485cb7a01acSMauro Carvalho Chehab 
1486cb7a01acSMauro Carvalho Chehab 	return 0;
1487cb7a01acSMauro Carvalho Chehab }
1488cb7a01acSMauro Carvalho Chehab 
1489cb7a01acSMauro Carvalho Chehab static int saa711x_g_input_status(struct v4l2_subdev *sd, u32 *status)
1490cb7a01acSMauro Carvalho Chehab {
1491cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1492cb7a01acSMauro Carvalho Chehab 	int reg1e = 0x80;
1493cb7a01acSMauro Carvalho Chehab 	int reg1f;
1494cb7a01acSMauro Carvalho Chehab 
1495cb7a01acSMauro Carvalho Chehab 	*status = V4L2_IN_ST_NO_SIGNAL;
1496e1277110SHans Verkuil 	if (state->ident == SAA7115)
1497cb7a01acSMauro Carvalho Chehab 		reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1498cb7a01acSMauro Carvalho Chehab 	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1499cb7a01acSMauro Carvalho Chehab 	if ((reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80)
1500cb7a01acSMauro Carvalho Chehab 		*status = 0;
1501cb7a01acSMauro Carvalho Chehab 	return 0;
1502cb7a01acSMauro Carvalho Chehab }
1503cb7a01acSMauro Carvalho Chehab 
1504cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1505cb7a01acSMauro Carvalho Chehab static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1506cb7a01acSMauro Carvalho Chehab {
1507cb7a01acSMauro Carvalho Chehab 	reg->val = saa711x_read(sd, reg->reg & 0xff);
1508cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
1509cb7a01acSMauro Carvalho Chehab 	return 0;
1510cb7a01acSMauro Carvalho Chehab }
1511cb7a01acSMauro Carvalho Chehab 
1512977ba3b1SHans Verkuil static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
1513cb7a01acSMauro Carvalho Chehab {
1514cb7a01acSMauro Carvalho Chehab 	saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
1515cb7a01acSMauro Carvalho Chehab 	return 0;
1516cb7a01acSMauro Carvalho Chehab }
1517cb7a01acSMauro Carvalho Chehab #endif
1518cb7a01acSMauro Carvalho Chehab 
1519cb7a01acSMauro Carvalho Chehab static int saa711x_log_status(struct v4l2_subdev *sd)
1520cb7a01acSMauro Carvalho Chehab {
1521cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state = to_state(sd);
1522cb7a01acSMauro Carvalho Chehab 	int reg1e, reg1f;
1523cb7a01acSMauro Carvalho Chehab 	int signalOk;
1524cb7a01acSMauro Carvalho Chehab 	int vcr;
1525cb7a01acSMauro Carvalho Chehab 
1526cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
1527e1277110SHans Verkuil 	if (state->ident != SAA7115) {
1528cb7a01acSMauro Carvalho Chehab 		/* status for the saa7114 */
1529cb7a01acSMauro Carvalho Chehab 		reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1530cb7a01acSMauro Carvalho Chehab 		signalOk = (reg1f & 0xc1) == 0x81;
1531cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Video signal:    %s\n", signalOk ? "ok" : "bad");
1532cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
1533cb7a01acSMauro Carvalho Chehab 		return 0;
1534cb7a01acSMauro Carvalho Chehab 	}
1535cb7a01acSMauro Carvalho Chehab 
1536cb7a01acSMauro Carvalho Chehab 	/* status for the saa7115 */
1537cb7a01acSMauro Carvalho Chehab 	reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
1538cb7a01acSMauro Carvalho Chehab 	reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
1539cb7a01acSMauro Carvalho Chehab 
1540cb7a01acSMauro Carvalho Chehab 	signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
1541cb7a01acSMauro Carvalho Chehab 	vcr = !(reg1f & 0x10);
1542cb7a01acSMauro Carvalho Chehab 
1543cb7a01acSMauro Carvalho Chehab 	if (state->input >= 6)
1544cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Input:           S-Video %d\n", state->input - 6);
1545cb7a01acSMauro Carvalho Chehab 	else
1546cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Input:           Composite %d\n", state->input);
1547cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
1548cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
1549cb7a01acSMauro Carvalho Chehab 
1550cb7a01acSMauro Carvalho Chehab 	switch (reg1e & 0x03) {
1551cb7a01acSMauro Carvalho Chehab 	case 1:
1552cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Detected format: NTSC\n");
1553cb7a01acSMauro Carvalho Chehab 		break;
1554cb7a01acSMauro Carvalho Chehab 	case 2:
1555cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Detected format: PAL\n");
1556cb7a01acSMauro Carvalho Chehab 		break;
1557cb7a01acSMauro Carvalho Chehab 	case 3:
1558cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Detected format: SECAM\n");
1559cb7a01acSMauro Carvalho Chehab 		break;
1560cb7a01acSMauro Carvalho Chehab 	default:
1561cb7a01acSMauro Carvalho Chehab 		v4l2_info(sd, "Detected format: BW/No color\n");
1562cb7a01acSMauro Carvalho Chehab 		break;
1563cb7a01acSMauro Carvalho Chehab 	}
1564cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "Width, Height:   %d, %d\n", state->width, state->height);
1565cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1566cb7a01acSMauro Carvalho Chehab 	return 0;
1567cb7a01acSMauro Carvalho Chehab }
1568cb7a01acSMauro Carvalho Chehab 
1569cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1570cb7a01acSMauro Carvalho Chehab 
1571cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
1572cb7a01acSMauro Carvalho Chehab 	.s_ctrl = saa711x_s_ctrl,
1573cb7a01acSMauro Carvalho Chehab 	.g_volatile_ctrl = saa711x_g_volatile_ctrl,
1574cb7a01acSMauro Carvalho Chehab };
1575cb7a01acSMauro Carvalho Chehab 
1576cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops saa711x_core_ops = {
1577cb7a01acSMauro Carvalho Chehab 	.log_status = saa711x_log_status,
1578cb7a01acSMauro Carvalho Chehab 	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
1579cb7a01acSMauro Carvalho Chehab 	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
1580cb7a01acSMauro Carvalho Chehab 	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
1581cb7a01acSMauro Carvalho Chehab 	.g_ctrl = v4l2_subdev_g_ctrl,
1582cb7a01acSMauro Carvalho Chehab 	.s_ctrl = v4l2_subdev_s_ctrl,
1583cb7a01acSMauro Carvalho Chehab 	.queryctrl = v4l2_subdev_queryctrl,
1584cb7a01acSMauro Carvalho Chehab 	.querymenu = v4l2_subdev_querymenu,
1585cb7a01acSMauro Carvalho Chehab 	.s_std = saa711x_s_std,
1586cb7a01acSMauro Carvalho Chehab 	.reset = saa711x_reset,
1587cb7a01acSMauro Carvalho Chehab 	.s_gpio = saa711x_s_gpio,
1588cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
1589cb7a01acSMauro Carvalho Chehab 	.g_register = saa711x_g_register,
1590cb7a01acSMauro Carvalho Chehab 	.s_register = saa711x_s_register,
1591cb7a01acSMauro Carvalho Chehab #endif
1592cb7a01acSMauro Carvalho Chehab };
1593cb7a01acSMauro Carvalho Chehab 
1594cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
1595cb7a01acSMauro Carvalho Chehab 	.s_radio = saa711x_s_radio,
1596cb7a01acSMauro Carvalho Chehab 	.g_tuner = saa711x_g_tuner,
1597cb7a01acSMauro Carvalho Chehab };
1598cb7a01acSMauro Carvalho Chehab 
1599cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
1600cb7a01acSMauro Carvalho Chehab 	.s_clock_freq = saa711x_s_clock_freq,
1601cb7a01acSMauro Carvalho Chehab };
1602cb7a01acSMauro Carvalho Chehab 
1603cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops saa711x_video_ops = {
1604cb7a01acSMauro Carvalho Chehab 	.s_routing = saa711x_s_routing,
1605cb7a01acSMauro Carvalho Chehab 	.s_crystal_freq = saa711x_s_crystal_freq,
1606cb7a01acSMauro Carvalho Chehab 	.s_mbus_fmt = saa711x_s_mbus_fmt,
1607cb7a01acSMauro Carvalho Chehab 	.s_stream = saa711x_s_stream,
1608cb7a01acSMauro Carvalho Chehab 	.querystd = saa711x_querystd,
1609cb7a01acSMauro Carvalho Chehab 	.g_input_status = saa711x_g_input_status,
1610cb7a01acSMauro Carvalho Chehab };
1611cb7a01acSMauro Carvalho Chehab 
1612cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops saa711x_vbi_ops = {
1613cb7a01acSMauro Carvalho Chehab 	.g_vbi_data = saa711x_g_vbi_data,
1614cb7a01acSMauro Carvalho Chehab 	.decode_vbi_line = saa711x_decode_vbi_line,
1615cb7a01acSMauro Carvalho Chehab 	.g_sliced_fmt = saa711x_g_sliced_fmt,
1616cb7a01acSMauro Carvalho Chehab 	.s_sliced_fmt = saa711x_s_sliced_fmt,
1617cb7a01acSMauro Carvalho Chehab 	.s_raw_fmt = saa711x_s_raw_fmt,
1618cb7a01acSMauro Carvalho Chehab };
1619cb7a01acSMauro Carvalho Chehab 
1620cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops saa711x_ops = {
1621cb7a01acSMauro Carvalho Chehab 	.core = &saa711x_core_ops,
1622cb7a01acSMauro Carvalho Chehab 	.tuner = &saa711x_tuner_ops,
1623cb7a01acSMauro Carvalho Chehab 	.audio = &saa711x_audio_ops,
1624cb7a01acSMauro Carvalho Chehab 	.video = &saa711x_video_ops,
1625cb7a01acSMauro Carvalho Chehab 	.vbi = &saa711x_vbi_ops,
1626cb7a01acSMauro Carvalho Chehab };
1627cb7a01acSMauro Carvalho Chehab 
16286a084d6bSMauro Carvalho Chehab #define CHIP_VER_SIZE	16
16296a084d6bSMauro Carvalho Chehab 
1630cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1631cb7a01acSMauro Carvalho Chehab 
16322ccf12afSJon Arne Jørgensen static void saa711x_write_platform_data(struct saa711x_state *state,
16332ccf12afSJon Arne Jørgensen 					struct saa7115_platform_data *data)
16342ccf12afSJon Arne Jørgensen {
16352ccf12afSJon Arne Jørgensen 	struct v4l2_subdev *sd = &state->sd;
16362ccf12afSJon Arne Jørgensen 	u8 work;
16372ccf12afSJon Arne Jørgensen 
16382ccf12afSJon Arne Jørgensen 	if (state->ident != GM7113C &&
16392ccf12afSJon Arne Jørgensen 	    state->ident != SAA7113)
16402ccf12afSJon Arne Jørgensen 		return;
16412ccf12afSJon Arne Jørgensen 
16422ccf12afSJon Arne Jørgensen 	if (data->saa7113_r08_htc) {
16432ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_08_SYNC_CNTL);
16442ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_08_HTC_MASK;
16452ccf12afSJon Arne Jørgensen 		work |= ((*data->saa7113_r08_htc) << SAA7113_R_08_HTC_OFFSET);
16462ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_08_SYNC_CNTL, work);
16472ccf12afSJon Arne Jørgensen 	}
16482ccf12afSJon Arne Jørgensen 
16492ccf12afSJon Arne Jørgensen 	if (data->saa7113_r10_vrln) {
16502ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_10_CHROMA_CNTL_2);
16512ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_10_VRLN_MASK;
16522ccf12afSJon Arne Jørgensen 		if (*data->saa7113_r10_vrln)
16532ccf12afSJon Arne Jørgensen 			work |= (1 << SAA7113_R_10_VRLN_OFFSET);
16542ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_10_CHROMA_CNTL_2, work);
16552ccf12afSJon Arne Jørgensen 	}
16562ccf12afSJon Arne Jørgensen 
16572ccf12afSJon Arne Jørgensen 	if (data->saa7113_r10_ofts) {
16582ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_10_CHROMA_CNTL_2);
16592ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_10_OFTS_MASK;
16602ccf12afSJon Arne Jørgensen 		work |= (*data->saa7113_r10_ofts << SAA7113_R_10_OFTS_OFFSET);
16612ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_10_CHROMA_CNTL_2, work);
16622ccf12afSJon Arne Jørgensen 	}
16632ccf12afSJon Arne Jørgensen 
16642ccf12afSJon Arne Jørgensen 	if (data->saa7113_r12_rts0) {
16652ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_12_RT_SIGNAL_CNTL);
16662ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_12_RTS0_MASK;
16672ccf12afSJon Arne Jørgensen 		work |= (*data->saa7113_r12_rts0 << SAA7113_R_12_RTS0_OFFSET);
16682ccf12afSJon Arne Jørgensen 
16692ccf12afSJon Arne Jørgensen 		/* According to the datasheet,
16702ccf12afSJon Arne Jørgensen 		 * SAA7113_RTS_DOT_IN should only be used on RTS1 */
16712ccf12afSJon Arne Jørgensen 		WARN_ON(*data->saa7113_r12_rts0 == SAA7113_RTS_DOT_IN);
16722ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_12_RT_SIGNAL_CNTL, work);
16732ccf12afSJon Arne Jørgensen 	}
16742ccf12afSJon Arne Jørgensen 
16752ccf12afSJon Arne Jørgensen 	if (data->saa7113_r12_rts1) {
16762ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_12_RT_SIGNAL_CNTL);
16772ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_12_RTS1_MASK;
16782ccf12afSJon Arne Jørgensen 		work |= (*data->saa7113_r12_rts1 << SAA7113_R_12_RTS1_OFFSET);
16792ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_12_RT_SIGNAL_CNTL, work);
16802ccf12afSJon Arne Jørgensen 	}
16812ccf12afSJon Arne Jørgensen 
16822ccf12afSJon Arne Jørgensen 	if (data->saa7113_r13_adlsb) {
16832ccf12afSJon Arne Jørgensen 		work = saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL);
16842ccf12afSJon Arne Jørgensen 		work &= ~SAA7113_R_13_ADLSB_MASK;
16852ccf12afSJon Arne Jørgensen 		if (*data->saa7113_r13_adlsb)
16862ccf12afSJon Arne Jørgensen 			work |= (1 << SAA7113_R_13_ADLSB_OFFSET);
16872ccf12afSJon Arne Jørgensen 		saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL, work);
16882ccf12afSJon Arne Jørgensen 	}
16892ccf12afSJon Arne Jørgensen }
16902ccf12afSJon Arne Jørgensen 
1691e090901eSMauro Carvalho Chehab /**
1692e090901eSMauro Carvalho Chehab  * saa711x_detect_chip - Detects the saa711x (or clone) variant
1693e090901eSMauro Carvalho Chehab  * @client:		I2C client structure.
1694e090901eSMauro Carvalho Chehab  * @id:			I2C device ID structure.
1695e090901eSMauro Carvalho Chehab  * @name:		Name of the device to be filled.
1696e090901eSMauro Carvalho Chehab  *
1697e090901eSMauro Carvalho Chehab  * Detects the Philips/NXP saa711x chip, or some clone of it.
1698e090901eSMauro Carvalho Chehab  * if 'id' is NULL or id->driver_data is equal to 1, it auto-probes
1699e090901eSMauro Carvalho Chehab  * the analog demod.
1700e090901eSMauro Carvalho Chehab  * If the tuner is not found, it returns -ENODEV.
1701e090901eSMauro Carvalho Chehab  * If auto-detection is disabled and the tuner doesn't match what it was
170239c1cb2bSJonathan McCrohan  *	required, it returns -EINVAL and fills 'name'.
1703e090901eSMauro Carvalho Chehab  * If the chip is found, it returns the chip ID and fills 'name'.
1704e090901eSMauro Carvalho Chehab  */
1705e090901eSMauro Carvalho Chehab static int saa711x_detect_chip(struct i2c_client *client,
1706e090901eSMauro Carvalho Chehab 			       const struct i2c_device_id *id,
17076a084d6bSMauro Carvalho Chehab 			       char *name)
1708e090901eSMauro Carvalho Chehab {
17096a084d6bSMauro Carvalho Chehab 	char chip_ver[CHIP_VER_SIZE];
1710e090901eSMauro Carvalho Chehab 	char chip_id;
1711e090901eSMauro Carvalho Chehab 	int i;
1712e090901eSMauro Carvalho Chehab 	int autodetect;
1713e090901eSMauro Carvalho Chehab 
1714e090901eSMauro Carvalho Chehab 	autodetect = !id || id->driver_data == 1;
1715e090901eSMauro Carvalho Chehab 
1716e090901eSMauro Carvalho Chehab 	/* Read the chip version register */
17176a084d6bSMauro Carvalho Chehab 	for (i = 0; i < CHIP_VER_SIZE; i++) {
1718e090901eSMauro Carvalho Chehab 		i2c_smbus_write_byte_data(client, 0, i);
1719e090901eSMauro Carvalho Chehab 		chip_ver[i] = i2c_smbus_read_byte_data(client, 0);
1720e090901eSMauro Carvalho Chehab 		name[i] = (chip_ver[i] & 0x0f) + '0';
1721e090901eSMauro Carvalho Chehab 		if (name[i] > '9')
1722e090901eSMauro Carvalho Chehab 			name[i] += 'a' - '9' - 1;
1723e090901eSMauro Carvalho Chehab 	}
1724e090901eSMauro Carvalho Chehab 	name[i] = '\0';
1725e090901eSMauro Carvalho Chehab 
1726e090901eSMauro Carvalho Chehab 	/* Check if it is a Philips/NXP chip */
1727e090901eSMauro Carvalho Chehab 	if (!memcmp(name + 1, "f711", 4)) {
1728e090901eSMauro Carvalho Chehab 		chip_id = name[5];
17296a084d6bSMauro Carvalho Chehab 		snprintf(name, CHIP_VER_SIZE, "saa711%c", chip_id);
1730e090901eSMauro Carvalho Chehab 
1731e090901eSMauro Carvalho Chehab 		if (!autodetect && strcmp(name, id->name))
1732e090901eSMauro Carvalho Chehab 			return -EINVAL;
1733e090901eSMauro Carvalho Chehab 
1734e090901eSMauro Carvalho Chehab 		switch (chip_id) {
1735e090901eSMauro Carvalho Chehab 		case '1':
1736e090901eSMauro Carvalho Chehab 			if (chip_ver[0] & 0xf0) {
17376a084d6bSMauro Carvalho Chehab 				snprintf(name, CHIP_VER_SIZE, "saa711%ca", chip_id);
1738e090901eSMauro Carvalho Chehab 				v4l_info(client, "saa7111a variant found\n");
1739e1277110SHans Verkuil 				return SAA7111A;
1740e090901eSMauro Carvalho Chehab 			}
1741e1277110SHans Verkuil 			return SAA7111;
1742e090901eSMauro Carvalho Chehab 		case '3':
1743e1277110SHans Verkuil 			return SAA7113;
1744e090901eSMauro Carvalho Chehab 		case '4':
1745e1277110SHans Verkuil 			return SAA7114;
1746e090901eSMauro Carvalho Chehab 		case '5':
1747e1277110SHans Verkuil 			return SAA7115;
1748e090901eSMauro Carvalho Chehab 		case '8':
1749e1277110SHans Verkuil 			return SAA7118;
1750e090901eSMauro Carvalho Chehab 		default:
1751e090901eSMauro Carvalho Chehab 			v4l2_info(client,
1752e090901eSMauro Carvalho Chehab 				  "WARNING: Philips/NXP chip unknown - Falling back to saa7111\n");
1753e1277110SHans Verkuil 			return SAA7111;
1754e090901eSMauro Carvalho Chehab 		}
1755e090901eSMauro Carvalho Chehab 	}
1756e090901eSMauro Carvalho Chehab 
1757b11460b0SMauro Carvalho Chehab 	/* Check if it is a gm7113c */
1758b11460b0SMauro Carvalho Chehab 	if (!memcmp(name, "0000", 4)) {
1759b11460b0SMauro Carvalho Chehab 		chip_id = 0;
1760b11460b0SMauro Carvalho Chehab 		for (i = 0; i < 4; i++) {
1761b11460b0SMauro Carvalho Chehab 			chip_id = chip_id << 1;
1762b11460b0SMauro Carvalho Chehab 			chip_id |= (chip_ver[i] & 0x80) ? 1 : 0;
1763b11460b0SMauro Carvalho Chehab 		}
1764b11460b0SMauro Carvalho Chehab 
1765b11460b0SMauro Carvalho Chehab 		/*
1766b11460b0SMauro Carvalho Chehab 		 * Note: From the datasheet, only versions 1 and 2
1767b11460b0SMauro Carvalho Chehab 		 * exists. However, tests on a device labeled as:
1768b11460b0SMauro Carvalho Chehab 		 * "GM7113C 1145" returned "10" on all 16 chip
1769b11460b0SMauro Carvalho Chehab 		 * version (reg 0x00) reads. So, we need to also
1770b11460b0SMauro Carvalho Chehab 		 * accept at least verion 0. For now, let's just
1771b11460b0SMauro Carvalho Chehab 		 * assume that a device that returns "0000" for
1772b11460b0SMauro Carvalho Chehab 		 * the lower nibble is a gm7113c.
1773b11460b0SMauro Carvalho Chehab 		 */
1774b11460b0SMauro Carvalho Chehab 
17756a084d6bSMauro Carvalho Chehab 		strlcpy(name, "gm7113c", CHIP_VER_SIZE);
1776b11460b0SMauro Carvalho Chehab 
1777b11460b0SMauro Carvalho Chehab 		if (!autodetect && strcmp(name, id->name))
1778b11460b0SMauro Carvalho Chehab 			return -EINVAL;
1779b11460b0SMauro Carvalho Chehab 
1780b11460b0SMauro Carvalho Chehab 		v4l_dbg(1, debug, client,
1781b11460b0SMauro Carvalho Chehab 			"It seems to be a %s chip (%*ph) @ 0x%x.\n",
1782b11460b0SMauro Carvalho Chehab 			name, 16, chip_ver, client->addr << 1);
1783b11460b0SMauro Carvalho Chehab 
1784e1277110SHans Verkuil 		return GM7113C;
1785b11460b0SMauro Carvalho Chehab 	}
1786b11460b0SMauro Carvalho Chehab 
1787e090901eSMauro Carvalho Chehab 	/* Chip was not discovered. Return its ID and don't bind */
1788e090901eSMauro Carvalho Chehab 	v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n",
1789e090901eSMauro Carvalho Chehab 		16, chip_ver, client->addr << 1);
1790e090901eSMauro Carvalho Chehab 	return -ENODEV;
1791e090901eSMauro Carvalho Chehab }
1792e090901eSMauro Carvalho Chehab 
1793cb7a01acSMauro Carvalho Chehab static int saa711x_probe(struct i2c_client *client,
1794cb7a01acSMauro Carvalho Chehab 			 const struct i2c_device_id *id)
1795cb7a01acSMauro Carvalho Chehab {
1796cb7a01acSMauro Carvalho Chehab 	struct saa711x_state *state;
1797cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
1798cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler *hdl;
17992ccf12afSJon Arne Jørgensen 	struct saa7115_platform_data *pdata;
1800e090901eSMauro Carvalho Chehab 	int ident;
18016a084d6bSMauro Carvalho Chehab 	char name[CHIP_VER_SIZE + 1];
1802cb7a01acSMauro Carvalho Chehab 
1803cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
1804cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1805cb7a01acSMauro Carvalho Chehab 		return -EIO;
1806cb7a01acSMauro Carvalho Chehab 
18076a084d6bSMauro Carvalho Chehab 	ident = saa711x_detect_chip(client, id, name);
1808e090901eSMauro Carvalho Chehab 	if (ident == -EINVAL) {
1809e090901eSMauro Carvalho Chehab 		/* Chip exists, but doesn't match */
1810e090901eSMauro Carvalho Chehab 		v4l_warn(client, "found %s while %s was expected\n",
1811e090901eSMauro Carvalho Chehab 			 name, id->name);
1812cb7a01acSMauro Carvalho Chehab 		return -ENODEV;
1813cb7a01acSMauro Carvalho Chehab 	}
1814e090901eSMauro Carvalho Chehab 	if (ident < 0)
1815e090901eSMauro Carvalho Chehab 		return ident;
1816cb7a01acSMauro Carvalho Chehab 
1817e090901eSMauro Carvalho Chehab 	strlcpy(client->name, name, sizeof(client->name));
1818cb7a01acSMauro Carvalho Chehab 
1819c02b211dSLaurent Pinchart 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
1820cb7a01acSMauro Carvalho Chehab 	if (state == NULL)
1821cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
1822cb7a01acSMauro Carvalho Chehab 	sd = &state->sd;
1823cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
1824cb7a01acSMauro Carvalho Chehab 
1825e84e91eaSHans Verkuil 	v4l_info(client, "%s found @ 0x%x (%s)\n", name,
1826e84e91eaSHans Verkuil 		 client->addr << 1, client->adapter->name);
1827cb7a01acSMauro Carvalho Chehab 	hdl = &state->hdl;
1828cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(hdl, 6);
1829cb7a01acSMauro Carvalho Chehab 	/* add in ascending ID order */
1830cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1831cb7a01acSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1832cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1833cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CONTRAST, 0, 127, 1, 64);
1834cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1835cb7a01acSMauro Carvalho Chehab 			V4L2_CID_SATURATION, 0, 127, 1, 64);
1836cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1837cb7a01acSMauro Carvalho Chehab 			V4L2_CID_HUE, -128, 127, 1, 0);
1838cb7a01acSMauro Carvalho Chehab 	state->agc = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1839cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
1840cb7a01acSMauro Carvalho Chehab 	state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
1841cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40);
1842cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = hdl;
1843cb7a01acSMauro Carvalho Chehab 	if (hdl->error) {
1844cb7a01acSMauro Carvalho Chehab 		int err = hdl->error;
1845cb7a01acSMauro Carvalho Chehab 
1846cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(hdl);
1847cb7a01acSMauro Carvalho Chehab 		return err;
1848cb7a01acSMauro Carvalho Chehab 	}
1849cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_auto_cluster(2, &state->agc, 0, true);
1850cb7a01acSMauro Carvalho Chehab 
1851cb7a01acSMauro Carvalho Chehab 	state->input = -1;
1852cb7a01acSMauro Carvalho Chehab 	state->output = SAA7115_IPORT_ON;
1853cb7a01acSMauro Carvalho Chehab 	state->enable = 1;
1854cb7a01acSMauro Carvalho Chehab 	state->radio = 0;
1855e090901eSMauro Carvalho Chehab 	state->ident = ident;
1856cb7a01acSMauro Carvalho Chehab 
1857cb7a01acSMauro Carvalho Chehab 	state->audclk_freq = 48000;
1858cb7a01acSMauro Carvalho Chehab 
1859cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "writing init values\n");
1860cb7a01acSMauro Carvalho Chehab 
1861cb7a01acSMauro Carvalho Chehab 	/* init to 60hz/48khz */
1862cb7a01acSMauro Carvalho Chehab 	state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
18632ccf12afSJon Arne Jørgensen 	pdata = client->dev.platform_data;
1864cb7a01acSMauro Carvalho Chehab 	switch (state->ident) {
1865e1277110SHans Verkuil 	case SAA7111:
1866e1277110SHans Verkuil 	case SAA7111A:
1867cb7a01acSMauro Carvalho Chehab 		saa711x_writeregs(sd, saa7111_init);
1868cb7a01acSMauro Carvalho Chehab 		break;
1869e1277110SHans Verkuil 	case GM7113C:
18702ccf12afSJon Arne Jørgensen 		saa711x_writeregs(sd, gm7113c_init);
18712ccf12afSJon Arne Jørgensen 		break;
1872e1277110SHans Verkuil 	case SAA7113:
18732ccf12afSJon Arne Jørgensen 		if (pdata && pdata->saa7113_force_gm7113c_init)
18742ccf12afSJon Arne Jørgensen 			saa711x_writeregs(sd, gm7113c_init);
18752ccf12afSJon Arne Jørgensen 		else
1876cb7a01acSMauro Carvalho Chehab 			saa711x_writeregs(sd, saa7113_init);
1877cb7a01acSMauro Carvalho Chehab 		break;
1878cb7a01acSMauro Carvalho Chehab 	default:
1879cb7a01acSMauro Carvalho Chehab 		state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
1880cb7a01acSMauro Carvalho Chehab 		saa711x_writeregs(sd, saa7115_init_auto_input);
1881cb7a01acSMauro Carvalho Chehab 	}
1882b9798bc1SJon Arne Jørgensen 	if (state->ident > SAA7111A && state->ident != GM7113C)
1883cb7a01acSMauro Carvalho Chehab 		saa711x_writeregs(sd, saa7115_init_misc);
18842ccf12afSJon Arne Jørgensen 
18852ccf12afSJon Arne Jørgensen 	if (pdata)
18862ccf12afSJon Arne Jørgensen 		saa711x_write_platform_data(state, pdata);
18872ccf12afSJon Arne Jørgensen 
1888cb7a01acSMauro Carvalho Chehab 	saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
1889cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_setup(hdl);
1890cb7a01acSMauro Carvalho Chehab 
1891cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
1892cb7a01acSMauro Carvalho Chehab 		saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
1893cb7a01acSMauro Carvalho Chehab 		saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
1894cb7a01acSMauro Carvalho Chehab 	return 0;
1895cb7a01acSMauro Carvalho Chehab }
1896cb7a01acSMauro Carvalho Chehab 
1897cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1898cb7a01acSMauro Carvalho Chehab 
1899cb7a01acSMauro Carvalho Chehab static int saa711x_remove(struct i2c_client *client)
1900cb7a01acSMauro Carvalho Chehab {
1901cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1902cb7a01acSMauro Carvalho Chehab 
1903cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
1904cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1905cb7a01acSMauro Carvalho Chehab 	return 0;
1906cb7a01acSMauro Carvalho Chehab }
1907cb7a01acSMauro Carvalho Chehab 
1908cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id saa711x_id[] = {
1909cb7a01acSMauro Carvalho Chehab 	{ "saa7115_auto", 1 }, /* autodetect */
1910cb7a01acSMauro Carvalho Chehab 	{ "saa7111", 0 },
1911cb7a01acSMauro Carvalho Chehab 	{ "saa7113", 0 },
1912cb7a01acSMauro Carvalho Chehab 	{ "saa7114", 0 },
1913cb7a01acSMauro Carvalho Chehab 	{ "saa7115", 0 },
1914cb7a01acSMauro Carvalho Chehab 	{ "saa7118", 0 },
1915b11460b0SMauro Carvalho Chehab 	{ "gm7113c", 0 },
1916cb7a01acSMauro Carvalho Chehab 	{ }
1917cb7a01acSMauro Carvalho Chehab };
1918cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, saa711x_id);
1919cb7a01acSMauro Carvalho Chehab 
1920cb7a01acSMauro Carvalho Chehab static struct i2c_driver saa711x_driver = {
1921cb7a01acSMauro Carvalho Chehab 	.driver = {
1922cb7a01acSMauro Carvalho Chehab 		.owner	= THIS_MODULE,
1923cb7a01acSMauro Carvalho Chehab 		.name	= "saa7115",
1924cb7a01acSMauro Carvalho Chehab 	},
1925cb7a01acSMauro Carvalho Chehab 	.probe		= saa711x_probe,
1926cb7a01acSMauro Carvalho Chehab 	.remove		= saa711x_remove,
1927cb7a01acSMauro Carvalho Chehab 	.id_table	= saa711x_id,
1928cb7a01acSMauro Carvalho Chehab };
1929cb7a01acSMauro Carvalho Chehab 
1930cb7a01acSMauro Carvalho Chehab module_i2c_driver(saa711x_driver);
1931