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