xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/adv7175.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  adv7175 - adv7175a video encoder driver version 0.0.3
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
6*4882a593Smuzhiyun  * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
7*4882a593Smuzhiyun  * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
8*4882a593Smuzhiyun  *    - some corrections for Pinnacle Systems Inc. DC10plus card.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
11*4882a593Smuzhiyun  *    - moved over to linux>=2.4.x i2c protocol (9/9/2002)
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/types.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/ioctl.h>
18*4882a593Smuzhiyun #include <linux/uaccess.h>
19*4882a593Smuzhiyun #include <linux/i2c.h>
20*4882a593Smuzhiyun #include <linux/videodev2.h>
21*4882a593Smuzhiyun #include <media/v4l2-device.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
24*4882a593Smuzhiyun MODULE_AUTHOR("Dave Perks");
25*4882a593Smuzhiyun MODULE_LICENSE("GPL");
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define   I2C_ADV7175        0xd4
28*4882a593Smuzhiyun #define   I2C_ADV7176        0x54
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static int debug;
32*4882a593Smuzhiyun module_param(debug, int, 0);
33*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "Debug level (0-1)");
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct adv7175 {
38*4882a593Smuzhiyun 	struct v4l2_subdev sd;
39*4882a593Smuzhiyun 	v4l2_std_id norm;
40*4882a593Smuzhiyun 	int input;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
to_adv7175(struct v4l2_subdev * sd)43*4882a593Smuzhiyun static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	return container_of(sd, struct adv7175, sd);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static char *inputs[] = { "pass_through", "play_back", "color_bar" };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static u32 adv7175_codes[] = {
51*4882a593Smuzhiyun 	MEDIA_BUS_FMT_UYVY8_2X8,
52*4882a593Smuzhiyun 	MEDIA_BUS_FMT_UYVY8_1X16,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
56*4882a593Smuzhiyun 
adv7175_write(struct v4l2_subdev * sd,u8 reg,u8 value)57*4882a593Smuzhiyun static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	return i2c_smbus_write_byte_data(client, reg, value);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
adv7175_read(struct v4l2_subdev * sd,u8 reg)64*4882a593Smuzhiyun static inline int adv7175_read(struct v4l2_subdev *sd, u8 reg)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	return i2c_smbus_read_byte_data(client, reg);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
adv7175_write_block(struct v4l2_subdev * sd,const u8 * data,unsigned int len)71*4882a593Smuzhiyun static int adv7175_write_block(struct v4l2_subdev *sd,
72*4882a593Smuzhiyun 		     const u8 *data, unsigned int len)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
75*4882a593Smuzhiyun 	int ret = -1;
76*4882a593Smuzhiyun 	u8 reg;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* the adv7175 has an autoincrement function, use it if
79*4882a593Smuzhiyun 	 * the adapter understands raw I2C */
80*4882a593Smuzhiyun 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
81*4882a593Smuzhiyun 		/* do raw I2C, not smbus compatible */
82*4882a593Smuzhiyun 		u8 block_data[32];
83*4882a593Smuzhiyun 		int block_len;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 		while (len >= 2) {
86*4882a593Smuzhiyun 			block_len = 0;
87*4882a593Smuzhiyun 			block_data[block_len++] = reg = data[0];
88*4882a593Smuzhiyun 			do {
89*4882a593Smuzhiyun 				block_data[block_len++] = data[1];
90*4882a593Smuzhiyun 				reg++;
91*4882a593Smuzhiyun 				len -= 2;
92*4882a593Smuzhiyun 				data += 2;
93*4882a593Smuzhiyun 			} while (len >= 2 && data[0] == reg && block_len < 32);
94*4882a593Smuzhiyun 			ret = i2c_master_send(client, block_data, block_len);
95*4882a593Smuzhiyun 			if (ret < 0)
96*4882a593Smuzhiyun 				break;
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 	} else {
99*4882a593Smuzhiyun 		/* do some slow I2C emulation kind of thing */
100*4882a593Smuzhiyun 		while (len >= 2) {
101*4882a593Smuzhiyun 			reg = *data++;
102*4882a593Smuzhiyun 			ret = adv7175_write(sd, reg, *data++);
103*4882a593Smuzhiyun 			if (ret < 0)
104*4882a593Smuzhiyun 				break;
105*4882a593Smuzhiyun 			len -= 2;
106*4882a593Smuzhiyun 		}
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return ret;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
set_subcarrier_freq(struct v4l2_subdev * sd,int pass_through)112*4882a593Smuzhiyun static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	/* for some reason pass_through NTSC needs
115*4882a593Smuzhiyun 	 * a different sub-carrier freq to remain stable. */
116*4882a593Smuzhiyun 	if (pass_through)
117*4882a593Smuzhiyun 		adv7175_write(sd, 0x02, 0x00);
118*4882a593Smuzhiyun 	else
119*4882a593Smuzhiyun 		adv7175_write(sd, 0x02, 0x55);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	adv7175_write(sd, 0x03, 0x55);
122*4882a593Smuzhiyun 	adv7175_write(sd, 0x04, 0x55);
123*4882a593Smuzhiyun 	adv7175_write(sd, 0x05, 0x25);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
127*4882a593Smuzhiyun /* Output filter:  S-Video  Composite */
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun #define MR050       0x11	/* 0x09 */
130*4882a593Smuzhiyun #define MR060       0x14	/* 0x0c */
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #define TR0MODE     0x46
135*4882a593Smuzhiyun #define TR0RST	    0x80
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun #define TR1CAPT	    0x80
138*4882a593Smuzhiyun #define TR1PLAY	    0x00
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static const unsigned char init_common[] = {
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	0x00, MR050,		/* MR0, PAL enabled */
143*4882a593Smuzhiyun 	0x01, 0x00,		/* MR1 */
144*4882a593Smuzhiyun 	0x02, 0x0c,		/* subc. freq. */
145*4882a593Smuzhiyun 	0x03, 0x8c,		/* subc. freq. */
146*4882a593Smuzhiyun 	0x04, 0x79,		/* subc. freq. */
147*4882a593Smuzhiyun 	0x05, 0x26,		/* subc. freq. */
148*4882a593Smuzhiyun 	0x06, 0x40,		/* subc. phase */
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	0x07, TR0MODE,		/* TR0, 16bit */
151*4882a593Smuzhiyun 	0x08, 0x21,		/*  */
152*4882a593Smuzhiyun 	0x09, 0x00,		/*  */
153*4882a593Smuzhiyun 	0x0a, 0x00,		/*  */
154*4882a593Smuzhiyun 	0x0b, 0x00,		/*  */
155*4882a593Smuzhiyun 	0x0c, TR1CAPT,		/* TR1 */
156*4882a593Smuzhiyun 	0x0d, 0x4f,		/* MR2 */
157*4882a593Smuzhiyun 	0x0e, 0x00,		/*  */
158*4882a593Smuzhiyun 	0x0f, 0x00,		/*  */
159*4882a593Smuzhiyun 	0x10, 0x00,		/*  */
160*4882a593Smuzhiyun 	0x11, 0x00,		/*  */
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static const unsigned char init_pal[] = {
164*4882a593Smuzhiyun 	0x00, MR050,		/* MR0, PAL enabled */
165*4882a593Smuzhiyun 	0x01, 0x00,		/* MR1 */
166*4882a593Smuzhiyun 	0x02, 0x0c,		/* subc. freq. */
167*4882a593Smuzhiyun 	0x03, 0x8c,		/* subc. freq. */
168*4882a593Smuzhiyun 	0x04, 0x79,		/* subc. freq. */
169*4882a593Smuzhiyun 	0x05, 0x26,		/* subc. freq. */
170*4882a593Smuzhiyun 	0x06, 0x40,		/* subc. phase */
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static const unsigned char init_ntsc[] = {
174*4882a593Smuzhiyun 	0x00, MR060,		/* MR0, NTSC enabled */
175*4882a593Smuzhiyun 	0x01, 0x00,		/* MR1 */
176*4882a593Smuzhiyun 	0x02, 0x55,		/* subc. freq. */
177*4882a593Smuzhiyun 	0x03, 0x55,		/* subc. freq. */
178*4882a593Smuzhiyun 	0x04, 0x55,		/* subc. freq. */
179*4882a593Smuzhiyun 	0x05, 0x25,		/* subc. freq. */
180*4882a593Smuzhiyun 	0x06, 0x1a,		/* subc. phase */
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun 
adv7175_init(struct v4l2_subdev * sd,u32 val)183*4882a593Smuzhiyun static int adv7175_init(struct v4l2_subdev *sd, u32 val)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	/* This is just for testing!!! */
186*4882a593Smuzhiyun 	adv7175_write_block(sd, init_common, sizeof(init_common));
187*4882a593Smuzhiyun 	adv7175_write(sd, 0x07, TR0MODE | TR0RST);
188*4882a593Smuzhiyun 	adv7175_write(sd, 0x07, TR0MODE);
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
adv7175_s_std_output(struct v4l2_subdev * sd,v4l2_std_id std)192*4882a593Smuzhiyun static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	struct adv7175 *encoder = to_adv7175(sd);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (std & V4L2_STD_NTSC) {
197*4882a593Smuzhiyun 		adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
198*4882a593Smuzhiyun 		if (encoder->input == 0)
199*4882a593Smuzhiyun 			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
200*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
201*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
202*4882a593Smuzhiyun 	} else if (std & V4L2_STD_PAL) {
203*4882a593Smuzhiyun 		adv7175_write_block(sd, init_pal, sizeof(init_pal));
204*4882a593Smuzhiyun 		if (encoder->input == 0)
205*4882a593Smuzhiyun 			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
206*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
207*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
208*4882a593Smuzhiyun 	} else if (std & V4L2_STD_SECAM) {
209*4882a593Smuzhiyun 		/* This is an attempt to convert
210*4882a593Smuzhiyun 		 * SECAM->PAL (typically it does not work
211*4882a593Smuzhiyun 		 * due to genlock: when decoder is in SECAM
212*4882a593Smuzhiyun 		 * and encoder in in PAL the subcarrier can
213*4882a593Smuzhiyun 		 * not be synchronized with horizontal
214*4882a593Smuzhiyun 		 * quency) */
215*4882a593Smuzhiyun 		adv7175_write_block(sd, init_pal, sizeof(init_pal));
216*4882a593Smuzhiyun 		if (encoder->input == 0)
217*4882a593Smuzhiyun 			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
218*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
219*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
220*4882a593Smuzhiyun 	} else {
221*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
222*4882a593Smuzhiyun 				(unsigned long long)std);
223*4882a593Smuzhiyun 		return -EINVAL;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
226*4882a593Smuzhiyun 	encoder->norm = std;
227*4882a593Smuzhiyun 	return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
adv7175_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)230*4882a593Smuzhiyun static int adv7175_s_routing(struct v4l2_subdev *sd,
231*4882a593Smuzhiyun 			     u32 input, u32 output, u32 config)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct adv7175 *encoder = to_adv7175(sd);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/* RJ: input = 0: input is from decoder
236*4882a593Smuzhiyun 	   input = 1: input is from ZR36060
237*4882a593Smuzhiyun 	   input = 2: color bar */
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	switch (input) {
240*4882a593Smuzhiyun 	case 0:
241*4882a593Smuzhiyun 		adv7175_write(sd, 0x01, 0x00);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 		if (encoder->norm & V4L2_STD_NTSC)
244*4882a593Smuzhiyun 			set_subcarrier_freq(sd, 1);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		adv7175_write(sd, 0x0c, TR1CAPT);	/* TR1 */
247*4882a593Smuzhiyun 		if (encoder->norm & V4L2_STD_SECAM)
248*4882a593Smuzhiyun 			adv7175_write(sd, 0x0d, 0x49);	/* Disable genlock */
249*4882a593Smuzhiyun 		else
250*4882a593Smuzhiyun 			adv7175_write(sd, 0x0d, 0x4f);	/* Enable genlock */
251*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
252*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
253*4882a593Smuzhiyun 		/*udelay(10);*/
254*4882a593Smuzhiyun 		break;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	case 1:
257*4882a593Smuzhiyun 		adv7175_write(sd, 0x01, 0x00);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		if (encoder->norm & V4L2_STD_NTSC)
260*4882a593Smuzhiyun 			set_subcarrier_freq(sd, 0);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		adv7175_write(sd, 0x0c, TR1PLAY);	/* TR1 */
263*4882a593Smuzhiyun 		adv7175_write(sd, 0x0d, 0x49);
264*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
265*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
266*4882a593Smuzhiyun 		/* udelay(10); */
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	case 2:
270*4882a593Smuzhiyun 		adv7175_write(sd, 0x01, 0x80);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		if (encoder->norm & V4L2_STD_NTSC)
273*4882a593Smuzhiyun 			set_subcarrier_freq(sd, 0);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		adv7175_write(sd, 0x0d, 0x49);
276*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE | TR0RST);
277*4882a593Smuzhiyun 		adv7175_write(sd, 0x07, TR0MODE);
278*4882a593Smuzhiyun 		/* udelay(10); */
279*4882a593Smuzhiyun 		break;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	default:
282*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
283*4882a593Smuzhiyun 		return -EINVAL;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
286*4882a593Smuzhiyun 	encoder->input = input;
287*4882a593Smuzhiyun 	return 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
adv7175_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)290*4882a593Smuzhiyun static int adv7175_enum_mbus_code(struct v4l2_subdev *sd,
291*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
292*4882a593Smuzhiyun 		struct v4l2_subdev_mbus_code_enum *code)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	if (code->pad || code->index >= ARRAY_SIZE(adv7175_codes))
295*4882a593Smuzhiyun 		return -EINVAL;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	code->code = adv7175_codes[code->index];
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
adv7175_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)301*4882a593Smuzhiyun static int adv7175_get_fmt(struct v4l2_subdev *sd,
302*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
303*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *mf = &format->format;
306*4882a593Smuzhiyun 	u8 val = adv7175_read(sd, 0x7);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (format->pad)
309*4882a593Smuzhiyun 		return -EINVAL;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	if ((val & 0x40) == (1 << 6))
312*4882a593Smuzhiyun 		mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
313*4882a593Smuzhiyun 	else
314*4882a593Smuzhiyun 		mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
317*4882a593Smuzhiyun 	mf->width       = 0;
318*4882a593Smuzhiyun 	mf->height      = 0;
319*4882a593Smuzhiyun 	mf->field       = V4L2_FIELD_ANY;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return 0;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
adv7175_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)324*4882a593Smuzhiyun static int adv7175_set_fmt(struct v4l2_subdev *sd,
325*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
326*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *mf = &format->format;
329*4882a593Smuzhiyun 	u8 val = adv7175_read(sd, 0x7);
330*4882a593Smuzhiyun 	int ret = 0;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (format->pad)
333*4882a593Smuzhiyun 		return -EINVAL;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	switch (mf->code) {
336*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_2X8:
337*4882a593Smuzhiyun 		val &= ~0x40;
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_1X16:
341*4882a593Smuzhiyun 		val |= 0x40;
342*4882a593Smuzhiyun 		break;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	default:
345*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd,
346*4882a593Smuzhiyun 			"illegal v4l2_mbus_framefmt code: %d\n", mf->code);
347*4882a593Smuzhiyun 		return -EINVAL;
348*4882a593Smuzhiyun 	}
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
351*4882a593Smuzhiyun 		ret = adv7175_write(sd, 0x7, val);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
adv7175_s_power(struct v4l2_subdev * sd,int on)356*4882a593Smuzhiyun static int adv7175_s_power(struct v4l2_subdev *sd, int on)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	if (on)
359*4882a593Smuzhiyun 		adv7175_write(sd, 0x01, 0x00);
360*4882a593Smuzhiyun 	else
361*4882a593Smuzhiyun 		adv7175_write(sd, 0x01, 0x78);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops adv7175_core_ops = {
369*4882a593Smuzhiyun 	.init = adv7175_init,
370*4882a593Smuzhiyun 	.s_power = adv7175_s_power,
371*4882a593Smuzhiyun };
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops adv7175_video_ops = {
374*4882a593Smuzhiyun 	.s_std_output = adv7175_s_std_output,
375*4882a593Smuzhiyun 	.s_routing = adv7175_s_routing,
376*4882a593Smuzhiyun };
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops adv7175_pad_ops = {
379*4882a593Smuzhiyun 	.enum_mbus_code = adv7175_enum_mbus_code,
380*4882a593Smuzhiyun 	.get_fmt = adv7175_get_fmt,
381*4882a593Smuzhiyun 	.set_fmt = adv7175_set_fmt,
382*4882a593Smuzhiyun };
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun static const struct v4l2_subdev_ops adv7175_ops = {
385*4882a593Smuzhiyun 	.core = &adv7175_core_ops,
386*4882a593Smuzhiyun 	.video = &adv7175_video_ops,
387*4882a593Smuzhiyun 	.pad = &adv7175_pad_ops,
388*4882a593Smuzhiyun };
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
391*4882a593Smuzhiyun 
adv7175_probe(struct i2c_client * client,const struct i2c_device_id * id)392*4882a593Smuzhiyun static int adv7175_probe(struct i2c_client *client,
393*4882a593Smuzhiyun 			const struct i2c_device_id *id)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	int i;
396*4882a593Smuzhiyun 	struct adv7175 *encoder;
397*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Check if the adapter supports the needed features */
400*4882a593Smuzhiyun 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
401*4882a593Smuzhiyun 		return -ENODEV;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	v4l_info(client, "chip found @ 0x%x (%s)\n",
404*4882a593Smuzhiyun 			client->addr << 1, client->adapter->name);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
407*4882a593Smuzhiyun 	if (encoder == NULL)
408*4882a593Smuzhiyun 		return -ENOMEM;
409*4882a593Smuzhiyun 	sd = &encoder->sd;
410*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
411*4882a593Smuzhiyun 	encoder->norm = V4L2_STD_NTSC;
412*4882a593Smuzhiyun 	encoder->input = 0;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	i = adv7175_write_block(sd, init_common, sizeof(init_common));
415*4882a593Smuzhiyun 	if (i >= 0) {
416*4882a593Smuzhiyun 		i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
417*4882a593Smuzhiyun 		i = adv7175_write(sd, 0x07, TR0MODE);
418*4882a593Smuzhiyun 		i = adv7175_read(sd, 0x12);
419*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 	if (i < 0)
422*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
423*4882a593Smuzhiyun 	return 0;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
adv7175_remove(struct i2c_client * client)426*4882a593Smuzhiyun static int adv7175_remove(struct i2c_client *client)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	v4l2_device_unregister_subdev(sd);
431*4882a593Smuzhiyun 	return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun /* ----------------------------------------------------------------------- */
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun static const struct i2c_device_id adv7175_id[] = {
437*4882a593Smuzhiyun 	{ "adv7175", 0 },
438*4882a593Smuzhiyun 	{ "adv7176", 0 },
439*4882a593Smuzhiyun 	{ }
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, adv7175_id);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun static struct i2c_driver adv7175_driver = {
444*4882a593Smuzhiyun 	.driver = {
445*4882a593Smuzhiyun 		.name	= "adv7175",
446*4882a593Smuzhiyun 	},
447*4882a593Smuzhiyun 	.probe		= adv7175_probe,
448*4882a593Smuzhiyun 	.remove		= adv7175_remove,
449*4882a593Smuzhiyun 	.id_table	= adv7175_id,
450*4882a593Smuzhiyun };
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun module_i2c_driver(adv7175_driver);
453