xref: /linux/drivers/media/i2c/adv7183.c (revision c771600c6af14749609b49565ffb4cac2959710d)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2202ea1f0SScott Jiang /*
3202ea1f0SScott Jiang  * adv7183.c Analog Devices ADV7183 video decoder driver
4202ea1f0SScott Jiang  *
5202ea1f0SScott Jiang  * Copyright (c) 2011 Analog Devices Inc.
6202ea1f0SScott Jiang  */
7202ea1f0SScott Jiang 
8202ea1f0SScott Jiang #include <linux/delay.h>
9202ea1f0SScott Jiang #include <linux/errno.h>
103e4fcec0SLinus Walleij #include <linux/gpio/consumer.h>
11202ea1f0SScott Jiang #include <linux/i2c.h>
12202ea1f0SScott Jiang #include <linux/init.h>
13202ea1f0SScott Jiang #include <linux/module.h>
14202ea1f0SScott Jiang #include <linux/slab.h>
15202ea1f0SScott Jiang #include <linux/types.h>
16202ea1f0SScott Jiang #include <linux/videodev2.h>
17202ea1f0SScott Jiang 
18b5dcee22SMauro Carvalho Chehab #include <media/i2c/adv7183.h>
19202ea1f0SScott Jiang #include <media/v4l2-ctrls.h>
20202ea1f0SScott Jiang #include <media/v4l2-device.h>
21202ea1f0SScott Jiang 
22202ea1f0SScott Jiang #include "adv7183_regs.h"
23202ea1f0SScott Jiang 
24202ea1f0SScott Jiang struct adv7183 {
25202ea1f0SScott Jiang 	struct v4l2_subdev sd;
26202ea1f0SScott Jiang 	struct v4l2_ctrl_handler hdl;
27202ea1f0SScott Jiang 
28202ea1f0SScott Jiang 	v4l2_std_id std; /* Current set standard */
29202ea1f0SScott Jiang 	u32 input;
30202ea1f0SScott Jiang 	u32 output;
313e4fcec0SLinus Walleij 	struct gpio_desc *reset_pin;
323e4fcec0SLinus Walleij 	struct gpio_desc *oe_pin;
33202ea1f0SScott Jiang 	struct v4l2_mbus_framefmt fmt;
34202ea1f0SScott Jiang };
35202ea1f0SScott Jiang 
36202ea1f0SScott Jiang /* EXAMPLES USING 27 MHz CLOCK
37202ea1f0SScott Jiang  * Mode 1 CVBS Input (Composite Video on AIN5)
38202ea1f0SScott Jiang  * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
39202ea1f0SScott Jiang  */
40202ea1f0SScott Jiang static const unsigned char adv7183_init_regs[] = {
41202ea1f0SScott Jiang 	ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
42202ea1f0SScott Jiang 	ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
43202ea1f0SScott Jiang 	ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
44202ea1f0SScott Jiang 	ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
45202ea1f0SScott Jiang 	ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
46202ea1f0SScott Jiang 	/* ADI recommended programming sequence */
47202ea1f0SScott Jiang 	ADV7183_ADI_CTRL, 0x80,
48202ea1f0SScott Jiang 	ADV7183_CTI_DNR_CTRL_4, 0x20,
49202ea1f0SScott Jiang 	0x52, 0x18,
50202ea1f0SScott Jiang 	0x58, 0xED,
51202ea1f0SScott Jiang 	0x77, 0xC5,
52202ea1f0SScott Jiang 	0x7C, 0x93,
53202ea1f0SScott Jiang 	0x7D, 0x00,
54202ea1f0SScott Jiang 	0xD0, 0x48,
55202ea1f0SScott Jiang 	0xD5, 0xA0,
56202ea1f0SScott Jiang 	0xD7, 0xEA,
57202ea1f0SScott Jiang 	ADV7183_SD_SATURATION_CR, 0x3E,
58202ea1f0SScott Jiang 	ADV7183_PAL_V_END, 0x3E,
59202ea1f0SScott Jiang 	ADV7183_PAL_F_TOGGLE, 0x0F,
60202ea1f0SScott Jiang 	ADV7183_ADI_CTRL, 0x00,
61202ea1f0SScott Jiang };
62202ea1f0SScott Jiang 
to_adv7183(struct v4l2_subdev * sd)63202ea1f0SScott Jiang static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
64202ea1f0SScott Jiang {
65202ea1f0SScott Jiang 	return container_of(sd, struct adv7183, sd);
66202ea1f0SScott Jiang }
to_sd(struct v4l2_ctrl * ctrl)67202ea1f0SScott Jiang static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
68202ea1f0SScott Jiang {
69202ea1f0SScott Jiang 	return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
70202ea1f0SScott Jiang }
71202ea1f0SScott Jiang 
adv7183_read(struct v4l2_subdev * sd,unsigned char reg)72202ea1f0SScott Jiang static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
73202ea1f0SScott Jiang {
74202ea1f0SScott Jiang 	struct i2c_client *client = v4l2_get_subdevdata(sd);
75202ea1f0SScott Jiang 
76202ea1f0SScott Jiang 	return i2c_smbus_read_byte_data(client, reg);
77202ea1f0SScott Jiang }
78202ea1f0SScott Jiang 
adv7183_write(struct v4l2_subdev * sd,unsigned char reg,unsigned char value)79202ea1f0SScott Jiang static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
80202ea1f0SScott Jiang 				unsigned char value)
81202ea1f0SScott Jiang {
82202ea1f0SScott Jiang 	struct i2c_client *client = v4l2_get_subdevdata(sd);
83202ea1f0SScott Jiang 
84202ea1f0SScott Jiang 	return i2c_smbus_write_byte_data(client, reg, value);
85202ea1f0SScott Jiang }
86202ea1f0SScott Jiang 
adv7183_writeregs(struct v4l2_subdev * sd,const unsigned char * regs,unsigned int num)87202ea1f0SScott Jiang static int adv7183_writeregs(struct v4l2_subdev *sd,
88202ea1f0SScott Jiang 		const unsigned char *regs, unsigned int num)
89202ea1f0SScott Jiang {
90202ea1f0SScott Jiang 	unsigned char reg, data;
91202ea1f0SScott Jiang 	unsigned int cnt = 0;
92202ea1f0SScott Jiang 
93202ea1f0SScott Jiang 	if (num & 0x1) {
94202ea1f0SScott Jiang 		v4l2_err(sd, "invalid regs array\n");
95202ea1f0SScott Jiang 		return -1;
96202ea1f0SScott Jiang 	}
97202ea1f0SScott Jiang 
98202ea1f0SScott Jiang 	while (cnt < num) {
99202ea1f0SScott Jiang 		reg = *regs++;
100202ea1f0SScott Jiang 		data = *regs++;
101202ea1f0SScott Jiang 		cnt += 2;
102202ea1f0SScott Jiang 
103202ea1f0SScott Jiang 		adv7183_write(sd, reg, data);
104202ea1f0SScott Jiang 	}
105202ea1f0SScott Jiang 	return 0;
106202ea1f0SScott Jiang }
107202ea1f0SScott Jiang 
adv7183_log_status(struct v4l2_subdev * sd)108202ea1f0SScott Jiang static int adv7183_log_status(struct v4l2_subdev *sd)
109202ea1f0SScott Jiang {
110202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
111202ea1f0SScott Jiang 
112202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
113202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_IN_CTRL));
114202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
115202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_VD_SEL));
116202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
117202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_OUT_CTRL));
118202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
119202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
120202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
121202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_AUTO_DET_EN));
122202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
123202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_CONTRAST));
124202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
125202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_BRIGHTNESS));
126202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
127202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_HUE));
128202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
129202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_DEF_Y));
130202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
131202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_DEF_C));
132202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
133202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_ADI_CTRL));
134202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
135202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_POW_MANAGE));
136202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
137202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_STATUS_1),
138202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_STATUS_2),
139202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_STATUS_3));
140202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
141202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_IDENT));
142202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
143202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
144202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
145202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
146202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
147202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
148202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
149202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
150202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
151202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
152202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_ADI_CTRL_2));
153202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
154202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
155202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
156202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
157202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
158202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
159202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
160202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
161202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
162202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
163202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
164202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
165202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
166202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
167202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
168202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
1696d3be300SMasanari Iida 	v4l2_info(sd, "adv7183: Hsync position control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
170202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
171202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
172202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
173202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
174202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_POLARITY));
175202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
176202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_ADC_CTRL));
177202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
178202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SD_OFFSET_CB),
179202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SD_OFFSET_CR));
180202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
181202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SD_SATURATION_CB),
182202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_SD_SATURATION_CR));
183202ea1f0SScott Jiang 	v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
184202ea1f0SScott Jiang 			adv7183_read(sd, ADV7183_DRIVE_STR));
185202ea1f0SScott Jiang 	v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
186202ea1f0SScott Jiang 	return 0;
187202ea1f0SScott Jiang }
188202ea1f0SScott Jiang 
adv7183_g_std(struct v4l2_subdev * sd,v4l2_std_id * std)189202ea1f0SScott Jiang static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
190202ea1f0SScott Jiang {
191202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
192202ea1f0SScott Jiang 
193202ea1f0SScott Jiang 	*std = decoder->std;
194202ea1f0SScott Jiang 	return 0;
195202ea1f0SScott Jiang }
196202ea1f0SScott Jiang 
adv7183_s_std(struct v4l2_subdev * sd,v4l2_std_id std)197202ea1f0SScott Jiang static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
198202ea1f0SScott Jiang {
199202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
200202ea1f0SScott Jiang 	int reg;
201202ea1f0SScott Jiang 
202202ea1f0SScott Jiang 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
203202ea1f0SScott Jiang 	if (std == V4L2_STD_PAL_60)
204202ea1f0SScott Jiang 		reg |= 0x60;
205202ea1f0SScott Jiang 	else if (std == V4L2_STD_NTSC_443)
206202ea1f0SScott Jiang 		reg |= 0x70;
207202ea1f0SScott Jiang 	else if (std == V4L2_STD_PAL_N)
208202ea1f0SScott Jiang 		reg |= 0x90;
209202ea1f0SScott Jiang 	else if (std == V4L2_STD_PAL_M)
210202ea1f0SScott Jiang 		reg |= 0xA0;
211202ea1f0SScott Jiang 	else if (std == V4L2_STD_PAL_Nc)
212202ea1f0SScott Jiang 		reg |= 0xC0;
213202ea1f0SScott Jiang 	else if (std & V4L2_STD_PAL)
214202ea1f0SScott Jiang 		reg |= 0x80;
215202ea1f0SScott Jiang 	else if (std & V4L2_STD_NTSC)
216202ea1f0SScott Jiang 		reg |= 0x50;
217202ea1f0SScott Jiang 	else if (std & V4L2_STD_SECAM)
218202ea1f0SScott Jiang 		reg |= 0xE0;
219202ea1f0SScott Jiang 	else
220202ea1f0SScott Jiang 		return -EINVAL;
221202ea1f0SScott Jiang 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
222202ea1f0SScott Jiang 
223202ea1f0SScott Jiang 	decoder->std = std;
224202ea1f0SScott Jiang 
225202ea1f0SScott Jiang 	return 0;
226202ea1f0SScott Jiang }
227202ea1f0SScott Jiang 
adv7183_reset(struct v4l2_subdev * sd,u32 val)228202ea1f0SScott Jiang static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
229202ea1f0SScott Jiang {
230202ea1f0SScott Jiang 	int reg;
231202ea1f0SScott Jiang 
232202ea1f0SScott Jiang 	reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
233202ea1f0SScott Jiang 	adv7183_write(sd, ADV7183_POW_MANAGE, reg);
234202ea1f0SScott Jiang 	/* wait 5ms before any further i2c writes are performed */
235202ea1f0SScott Jiang 	usleep_range(5000, 10000);
236202ea1f0SScott Jiang 	return 0;
237202ea1f0SScott Jiang }
238202ea1f0SScott Jiang 
adv7183_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)239202ea1f0SScott Jiang static int adv7183_s_routing(struct v4l2_subdev *sd,
240202ea1f0SScott Jiang 				u32 input, u32 output, u32 config)
241202ea1f0SScott Jiang {
242202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
243202ea1f0SScott Jiang 	int reg;
244202ea1f0SScott Jiang 
245202ea1f0SScott Jiang 	if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
246202ea1f0SScott Jiang 		return -EINVAL;
247202ea1f0SScott Jiang 
248202ea1f0SScott Jiang 	if (input != decoder->input) {
249202ea1f0SScott Jiang 		decoder->input = input;
250202ea1f0SScott Jiang 		reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
251202ea1f0SScott Jiang 		switch (input) {
252202ea1f0SScott Jiang 		case ADV7183_COMPOSITE1:
253202ea1f0SScott Jiang 			reg |= 0x1;
254202ea1f0SScott Jiang 			break;
255202ea1f0SScott Jiang 		case ADV7183_COMPOSITE2:
256202ea1f0SScott Jiang 			reg |= 0x2;
257202ea1f0SScott Jiang 			break;
258202ea1f0SScott Jiang 		case ADV7183_COMPOSITE3:
259202ea1f0SScott Jiang 			reg |= 0x3;
260202ea1f0SScott Jiang 			break;
261202ea1f0SScott Jiang 		case ADV7183_COMPOSITE4:
262202ea1f0SScott Jiang 			reg |= 0x4;
263202ea1f0SScott Jiang 			break;
264202ea1f0SScott Jiang 		case ADV7183_COMPOSITE5:
265202ea1f0SScott Jiang 			reg |= 0x5;
266202ea1f0SScott Jiang 			break;
267202ea1f0SScott Jiang 		case ADV7183_COMPOSITE6:
268202ea1f0SScott Jiang 			reg |= 0xB;
269202ea1f0SScott Jiang 			break;
270202ea1f0SScott Jiang 		case ADV7183_COMPOSITE7:
271202ea1f0SScott Jiang 			reg |= 0xC;
272202ea1f0SScott Jiang 			break;
273202ea1f0SScott Jiang 		case ADV7183_COMPOSITE8:
274202ea1f0SScott Jiang 			reg |= 0xD;
275202ea1f0SScott Jiang 			break;
276202ea1f0SScott Jiang 		case ADV7183_COMPOSITE9:
277202ea1f0SScott Jiang 			reg |= 0xE;
278202ea1f0SScott Jiang 			break;
279202ea1f0SScott Jiang 		case ADV7183_COMPOSITE10:
280202ea1f0SScott Jiang 			reg |= 0xF;
281202ea1f0SScott Jiang 			break;
282202ea1f0SScott Jiang 		case ADV7183_SVIDEO0:
283202ea1f0SScott Jiang 			reg |= 0x6;
284202ea1f0SScott Jiang 			break;
285202ea1f0SScott Jiang 		case ADV7183_SVIDEO1:
286202ea1f0SScott Jiang 			reg |= 0x7;
287202ea1f0SScott Jiang 			break;
288202ea1f0SScott Jiang 		case ADV7183_SVIDEO2:
289202ea1f0SScott Jiang 			reg |= 0x8;
290202ea1f0SScott Jiang 			break;
291202ea1f0SScott Jiang 		case ADV7183_COMPONENT0:
292202ea1f0SScott Jiang 			reg |= 0x9;
293202ea1f0SScott Jiang 			break;
294202ea1f0SScott Jiang 		case ADV7183_COMPONENT1:
295202ea1f0SScott Jiang 			reg |= 0xA;
296202ea1f0SScott Jiang 			break;
297202ea1f0SScott Jiang 		default:
298202ea1f0SScott Jiang 			break;
299202ea1f0SScott Jiang 		}
300202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_IN_CTRL, reg);
301202ea1f0SScott Jiang 	}
302202ea1f0SScott Jiang 
303202ea1f0SScott Jiang 	if (output != decoder->output) {
304202ea1f0SScott Jiang 		decoder->output = output;
305202ea1f0SScott Jiang 		reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
306202ea1f0SScott Jiang 		switch (output) {
307202ea1f0SScott Jiang 		case ADV7183_16BIT_OUT:
308202ea1f0SScott Jiang 			reg |= 0x9;
309202ea1f0SScott Jiang 			break;
310202ea1f0SScott Jiang 		default:
311202ea1f0SScott Jiang 			reg |= 0xC;
312202ea1f0SScott Jiang 			break;
313202ea1f0SScott Jiang 		}
314202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_OUT_CTRL, reg);
315202ea1f0SScott Jiang 	}
316202ea1f0SScott Jiang 
317202ea1f0SScott Jiang 	return 0;
318202ea1f0SScott Jiang }
319202ea1f0SScott Jiang 
adv7183_s_ctrl(struct v4l2_ctrl * ctrl)320202ea1f0SScott Jiang static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
321202ea1f0SScott Jiang {
322202ea1f0SScott Jiang 	struct v4l2_subdev *sd = to_sd(ctrl);
323202ea1f0SScott Jiang 	int val = ctrl->val;
324202ea1f0SScott Jiang 
325202ea1f0SScott Jiang 	switch (ctrl->id) {
326202ea1f0SScott Jiang 	case V4L2_CID_BRIGHTNESS:
327202ea1f0SScott Jiang 		if (val < 0)
328202ea1f0SScott Jiang 			val = 127 - val;
329202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_BRIGHTNESS, val);
330202ea1f0SScott Jiang 		break;
331202ea1f0SScott Jiang 	case V4L2_CID_CONTRAST:
332202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_CONTRAST, val);
333202ea1f0SScott Jiang 		break;
334202ea1f0SScott Jiang 	case V4L2_CID_SATURATION:
335202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
336202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
337202ea1f0SScott Jiang 		break;
338202ea1f0SScott Jiang 	case V4L2_CID_HUE:
339202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
340202ea1f0SScott Jiang 		adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
341202ea1f0SScott Jiang 		break;
342202ea1f0SScott Jiang 	default:
343202ea1f0SScott Jiang 		return -EINVAL;
344202ea1f0SScott Jiang 	}
345202ea1f0SScott Jiang 
346202ea1f0SScott Jiang 	return 0;
347202ea1f0SScott Jiang }
348202ea1f0SScott Jiang 
adv7183_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)349202ea1f0SScott Jiang static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
350202ea1f0SScott Jiang {
351202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
352202ea1f0SScott Jiang 	int reg;
353202ea1f0SScott Jiang 
354202ea1f0SScott Jiang 	/* enable autodetection block */
355202ea1f0SScott Jiang 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
356202ea1f0SScott Jiang 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
357202ea1f0SScott Jiang 
358202ea1f0SScott Jiang 	/* wait autodetection switch */
359202ea1f0SScott Jiang 	mdelay(10);
360202ea1f0SScott Jiang 
361202ea1f0SScott Jiang 	/* get autodetection result */
362202ea1f0SScott Jiang 	reg = adv7183_read(sd, ADV7183_STATUS_1);
363202ea1f0SScott Jiang 	switch ((reg >> 0x4) & 0x7) {
364202ea1f0SScott Jiang 	case 0:
3657dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC;
366202ea1f0SScott Jiang 		break;
367202ea1f0SScott Jiang 	case 1:
3687dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC_443;
369202ea1f0SScott Jiang 		break;
370202ea1f0SScott Jiang 	case 2:
3717dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_M;
372202ea1f0SScott Jiang 		break;
373202ea1f0SScott Jiang 	case 3:
3747dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_60;
375202ea1f0SScott Jiang 		break;
376202ea1f0SScott Jiang 	case 4:
3777dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL;
378202ea1f0SScott Jiang 		break;
379202ea1f0SScott Jiang 	case 5:
3807dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
381202ea1f0SScott Jiang 		break;
382202ea1f0SScott Jiang 	case 6:
3837dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_Nc;
384202ea1f0SScott Jiang 		break;
385202ea1f0SScott Jiang 	case 7:
3867dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
387202ea1f0SScott Jiang 		break;
388202ea1f0SScott Jiang 	default:
389202ea1f0SScott Jiang 		*std = V4L2_STD_UNKNOWN;
390202ea1f0SScott Jiang 		break;
391202ea1f0SScott Jiang 	}
392202ea1f0SScott Jiang 
393202ea1f0SScott Jiang 	/* after std detection, write back user set std */
394202ea1f0SScott Jiang 	adv7183_s_std(sd, decoder->std);
395202ea1f0SScott Jiang 	return 0;
396202ea1f0SScott Jiang }
397202ea1f0SScott Jiang 
adv7183_g_input_status(struct v4l2_subdev * sd,u32 * status)398202ea1f0SScott Jiang static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
399202ea1f0SScott Jiang {
400202ea1f0SScott Jiang 	int reg;
401202ea1f0SScott Jiang 
402202ea1f0SScott Jiang 	*status = V4L2_IN_ST_NO_SIGNAL;
403202ea1f0SScott Jiang 	reg = adv7183_read(sd, ADV7183_STATUS_1);
404202ea1f0SScott Jiang 	if (reg < 0)
405202ea1f0SScott Jiang 		return reg;
406202ea1f0SScott Jiang 	if (reg & 0x1)
407202ea1f0SScott Jiang 		*status = 0;
408202ea1f0SScott Jiang 	return 0;
409202ea1f0SScott Jiang }
410202ea1f0SScott Jiang 
adv7183_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)411ebcff5fcSHans Verkuil static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
4120d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
413ebcff5fcSHans Verkuil 		struct v4l2_subdev_mbus_code_enum *code)
414202ea1f0SScott Jiang {
415ebcff5fcSHans Verkuil 	if (code->pad || code->index > 0)
416202ea1f0SScott Jiang 		return -EINVAL;
417202ea1f0SScott Jiang 
418ebcff5fcSHans Verkuil 	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
419202ea1f0SScott Jiang 	return 0;
420202ea1f0SScott Jiang }
421202ea1f0SScott Jiang 
adv7183_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)422717fd5b4SHans Verkuil static int adv7183_set_fmt(struct v4l2_subdev *sd,
4230d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
424717fd5b4SHans Verkuil 		struct v4l2_subdev_format *format)
425202ea1f0SScott Jiang {
426202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
427717fd5b4SHans Verkuil 	struct v4l2_mbus_framefmt *fmt = &format->format;
428717fd5b4SHans Verkuil 
429717fd5b4SHans Verkuil 	if (format->pad)
430717fd5b4SHans Verkuil 		return -EINVAL;
431202ea1f0SScott Jiang 
432f5fe58fdSBoris BREZILLON 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
433202ea1f0SScott Jiang 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
434202ea1f0SScott Jiang 	if (decoder->std & V4L2_STD_525_60) {
435202ea1f0SScott Jiang 		fmt->field = V4L2_FIELD_SEQ_TB;
436202ea1f0SScott Jiang 		fmt->width = 720;
437202ea1f0SScott Jiang 		fmt->height = 480;
438202ea1f0SScott Jiang 	} else {
439202ea1f0SScott Jiang 		fmt->field = V4L2_FIELD_SEQ_BT;
440202ea1f0SScott Jiang 		fmt->width = 720;
441202ea1f0SScott Jiang 		fmt->height = 576;
442202ea1f0SScott Jiang 	}
443717fd5b4SHans Verkuil 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
444202ea1f0SScott Jiang 		decoder->fmt = *fmt;
445202ea1f0SScott Jiang 	return 0;
446202ea1f0SScott Jiang }
447202ea1f0SScott Jiang 
adv7183_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)448da298c6dSHans Verkuil static int adv7183_get_fmt(struct v4l2_subdev *sd,
4490d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
450da298c6dSHans Verkuil 		struct v4l2_subdev_format *format)
451202ea1f0SScott Jiang {
452202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
453202ea1f0SScott Jiang 
454da298c6dSHans Verkuil 	if (format->pad)
455da298c6dSHans Verkuil 		return -EINVAL;
456da298c6dSHans Verkuil 
457da298c6dSHans Verkuil 	format->format = decoder->fmt;
458202ea1f0SScott Jiang 	return 0;
459202ea1f0SScott Jiang }
460202ea1f0SScott Jiang 
adv7183_s_stream(struct v4l2_subdev * sd,int enable)461202ea1f0SScott Jiang static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
462202ea1f0SScott Jiang {
463202ea1f0SScott Jiang 	struct adv7183 *decoder = to_adv7183(sd);
464202ea1f0SScott Jiang 
465202ea1f0SScott Jiang 	if (enable)
4663e4fcec0SLinus Walleij 		gpiod_set_value(decoder->oe_pin, 1);
467202ea1f0SScott Jiang 	else
4683e4fcec0SLinus Walleij 		gpiod_set_value(decoder->oe_pin, 0);
469202ea1f0SScott Jiang 	udelay(1);
470202ea1f0SScott Jiang 	return 0;
471202ea1f0SScott Jiang }
472202ea1f0SScott Jiang 
473202ea1f0SScott Jiang #ifdef CONFIG_VIDEO_ADV_DEBUG
adv7183_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)474202ea1f0SScott Jiang static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
475202ea1f0SScott Jiang {
476202ea1f0SScott Jiang 	reg->val = adv7183_read(sd, reg->reg & 0xff);
477202ea1f0SScott Jiang 	reg->size = 1;
478202ea1f0SScott Jiang 	return 0;
479202ea1f0SScott Jiang }
480202ea1f0SScott Jiang 
adv7183_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)481977ba3b1SHans Verkuil static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
482202ea1f0SScott Jiang {
483202ea1f0SScott Jiang 	adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
484202ea1f0SScott Jiang 	return 0;
485202ea1f0SScott Jiang }
486202ea1f0SScott Jiang #endif
487202ea1f0SScott Jiang 
488202ea1f0SScott Jiang static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
489202ea1f0SScott Jiang 	.s_ctrl = adv7183_s_ctrl,
490202ea1f0SScott Jiang };
491202ea1f0SScott Jiang 
492202ea1f0SScott Jiang static const struct v4l2_subdev_core_ops adv7183_core_ops = {
493202ea1f0SScott Jiang 	.log_status = adv7183_log_status,
494202ea1f0SScott Jiang 	.reset = adv7183_reset,
495202ea1f0SScott Jiang #ifdef CONFIG_VIDEO_ADV_DEBUG
496202ea1f0SScott Jiang 	.g_register = adv7183_g_register,
497202ea1f0SScott Jiang 	.s_register = adv7183_s_register,
498202ea1f0SScott Jiang #endif
499202ea1f0SScott Jiang };
500202ea1f0SScott Jiang 
501202ea1f0SScott Jiang static const struct v4l2_subdev_video_ops adv7183_video_ops = {
5028774bed9SLaurent Pinchart 	.g_std = adv7183_g_std,
5038774bed9SLaurent Pinchart 	.s_std = adv7183_s_std,
504202ea1f0SScott Jiang 	.s_routing = adv7183_s_routing,
505202ea1f0SScott Jiang 	.querystd = adv7183_querystd,
506202ea1f0SScott Jiang 	.g_input_status = adv7183_g_input_status,
507202ea1f0SScott Jiang 	.s_stream = adv7183_s_stream,
508202ea1f0SScott Jiang };
509202ea1f0SScott Jiang 
510ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops adv7183_pad_ops = {
511ebcff5fcSHans Verkuil 	.enum_mbus_code = adv7183_enum_mbus_code,
512da298c6dSHans Verkuil 	.get_fmt = adv7183_get_fmt,
513717fd5b4SHans Verkuil 	.set_fmt = adv7183_set_fmt,
514ebcff5fcSHans Verkuil };
515ebcff5fcSHans Verkuil 
516202ea1f0SScott Jiang static const struct v4l2_subdev_ops adv7183_ops = {
517202ea1f0SScott Jiang 	.core = &adv7183_core_ops,
518202ea1f0SScott Jiang 	.video = &adv7183_video_ops,
519ebcff5fcSHans Verkuil 	.pad = &adv7183_pad_ops,
520202ea1f0SScott Jiang };
521202ea1f0SScott Jiang 
adv7183_probe(struct i2c_client * client)522f31dab40SUwe Kleine-König static int adv7183_probe(struct i2c_client *client)
523202ea1f0SScott Jiang {
524202ea1f0SScott Jiang 	struct adv7183 *decoder;
525202ea1f0SScott Jiang 	struct v4l2_subdev *sd;
526202ea1f0SScott Jiang 	struct v4l2_ctrl_handler *hdl;
527202ea1f0SScott Jiang 	int ret;
528717fd5b4SHans Verkuil 	struct v4l2_subdev_format fmt = {
529717fd5b4SHans Verkuil 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
530717fd5b4SHans Verkuil 	};
531202ea1f0SScott Jiang 
532202ea1f0SScott Jiang 	/* Check if the adapter supports the needed features */
533202ea1f0SScott Jiang 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
534202ea1f0SScott Jiang 		return -EIO;
535202ea1f0SScott Jiang 
536202ea1f0SScott Jiang 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
537202ea1f0SScott Jiang 			client->addr << 1, client->adapter->name);
538202ea1f0SScott Jiang 
539c02b211dSLaurent Pinchart 	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
540202ea1f0SScott Jiang 	if (decoder == NULL)
541202ea1f0SScott Jiang 		return -ENOMEM;
542202ea1f0SScott Jiang 
5433e4fcec0SLinus Walleij 	/*
5443e4fcec0SLinus Walleij 	 * Requesting high will assert reset, the line should be
5453e4fcec0SLinus Walleij 	 * flagged as active low in descriptor table or machine description.
5463e4fcec0SLinus Walleij 	 */
5473e4fcec0SLinus Walleij 	decoder->reset_pin = devm_gpiod_get(&client->dev, "reset",
5483e4fcec0SLinus Walleij 					    GPIOD_OUT_HIGH);
5493e4fcec0SLinus Walleij 	if (IS_ERR(decoder->reset_pin))
5503e4fcec0SLinus Walleij 		return PTR_ERR(decoder->reset_pin);
5513e4fcec0SLinus Walleij 	gpiod_set_consumer_name(decoder->reset_pin, "ADV7183 Reset");
5523e4fcec0SLinus Walleij 	/*
5533e4fcec0SLinus Walleij 	 * Requesting low will start with output disabled, the line should be
5543e4fcec0SLinus Walleij 	 * flagged as active low in descriptor table or machine description.
5553e4fcec0SLinus Walleij 	 */
5563e4fcec0SLinus Walleij 	decoder->oe_pin = devm_gpiod_get(&client->dev, "oe",
5573e4fcec0SLinus Walleij 					 GPIOD_OUT_LOW);
5583e4fcec0SLinus Walleij 	if (IS_ERR(decoder->oe_pin))
5593e4fcec0SLinus Walleij 		return PTR_ERR(decoder->oe_pin);
5603e4fcec0SLinus Walleij 	gpiod_set_consumer_name(decoder->reset_pin, "ADV7183 Output Enable");
561202ea1f0SScott Jiang 
562202ea1f0SScott Jiang 	sd = &decoder->sd;
563202ea1f0SScott Jiang 	v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
564202ea1f0SScott Jiang 
565202ea1f0SScott Jiang 	hdl = &decoder->hdl;
566202ea1f0SScott Jiang 	v4l2_ctrl_handler_init(hdl, 4);
567202ea1f0SScott Jiang 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
568202ea1f0SScott Jiang 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
569202ea1f0SScott Jiang 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
570202ea1f0SScott Jiang 			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
571202ea1f0SScott Jiang 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
572202ea1f0SScott Jiang 			V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
573202ea1f0SScott Jiang 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
574202ea1f0SScott Jiang 			V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
575202ea1f0SScott Jiang 	/* hook the control handler into the driver */
576202ea1f0SScott Jiang 	sd->ctrl_handler = hdl;
577202ea1f0SScott Jiang 	if (hdl->error) {
578202ea1f0SScott Jiang 		ret = hdl->error;
579202ea1f0SScott Jiang 
580202ea1f0SScott Jiang 		v4l2_ctrl_handler_free(hdl);
581b015ba29SLaurent Pinchart 		return ret;
582202ea1f0SScott Jiang 	}
583202ea1f0SScott Jiang 
584202ea1f0SScott Jiang 	/* v4l2 doesn't support an autodetect standard, pick PAL as default */
585202ea1f0SScott Jiang 	decoder->std = V4L2_STD_PAL;
586202ea1f0SScott Jiang 	decoder->input = ADV7183_COMPOSITE4;
587202ea1f0SScott Jiang 	decoder->output = ADV7183_8BIT_OUT;
588202ea1f0SScott Jiang 
589202ea1f0SScott Jiang 	/* reset chip */
590202ea1f0SScott Jiang 	/* reset pulse width at least 5ms */
591202ea1f0SScott Jiang 	mdelay(10);
5923e4fcec0SLinus Walleij 	/* De-assert reset line (descriptor tagged active low) */
5933e4fcec0SLinus Walleij 	gpiod_set_value(decoder->reset_pin, 0);
594202ea1f0SScott Jiang 	/* wait 5ms before any further i2c writes are performed */
595202ea1f0SScott Jiang 	mdelay(5);
596202ea1f0SScott Jiang 
597202ea1f0SScott Jiang 	adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
598202ea1f0SScott Jiang 	adv7183_s_std(sd, decoder->std);
599717fd5b4SHans Verkuil 	fmt.format.width = 720;
600717fd5b4SHans Verkuil 	fmt.format.height = 576;
601717fd5b4SHans Verkuil 	adv7183_set_fmt(sd, NULL, &fmt);
602202ea1f0SScott Jiang 
603202ea1f0SScott Jiang 	/* initialize the hardware to the default control values */
604202ea1f0SScott Jiang 	ret = v4l2_ctrl_handler_setup(hdl);
605202ea1f0SScott Jiang 	if (ret) {
606202ea1f0SScott Jiang 		v4l2_ctrl_handler_free(hdl);
607b015ba29SLaurent Pinchart 		return ret;
608202ea1f0SScott Jiang 	}
609202ea1f0SScott Jiang 
610202ea1f0SScott Jiang 	return 0;
611202ea1f0SScott Jiang }
612202ea1f0SScott Jiang 
adv7183_remove(struct i2c_client * client)613ed5c2f5fSUwe Kleine-König static void adv7183_remove(struct i2c_client *client)
614202ea1f0SScott Jiang {
615202ea1f0SScott Jiang 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
616202ea1f0SScott Jiang 
617202ea1f0SScott Jiang 	v4l2_device_unregister_subdev(sd);
618202ea1f0SScott Jiang 	v4l2_ctrl_handler_free(sd->ctrl_handler);
619202ea1f0SScott Jiang }
620202ea1f0SScott Jiang 
621202ea1f0SScott Jiang static const struct i2c_device_id adv7183_id[] = {
622cc4cbd4bSUwe Kleine-König 	{ "adv7183" },
623cc4cbd4bSUwe Kleine-König 	{}
624202ea1f0SScott Jiang };
625202ea1f0SScott Jiang 
626202ea1f0SScott Jiang MODULE_DEVICE_TABLE(i2c, adv7183_id);
627202ea1f0SScott Jiang 
628202ea1f0SScott Jiang static struct i2c_driver adv7183_driver = {
629202ea1f0SScott Jiang 	.driver = {
630202ea1f0SScott Jiang 		.name   = "adv7183",
631202ea1f0SScott Jiang 	},
632aaeb31c0SUwe Kleine-König 	.probe          = adv7183_probe,
6334c62e976SGreg Kroah-Hartman 	.remove         = adv7183_remove,
634202ea1f0SScott Jiang 	.id_table       = adv7183_id,
635202ea1f0SScott Jiang };
636202ea1f0SScott Jiang 
63701aea0bfSWei Yongjun module_i2c_driver(adv7183_driver);
638202ea1f0SScott Jiang 
639202ea1f0SScott Jiang MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
640202ea1f0SScott Jiang MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
641202ea1f0SScott Jiang MODULE_LICENSE("GPL v2");
642