xref: /openbmc/linux/drivers/media/i2c/adv7183.c (revision ebcff5fce6b189306756b0cb06779e15f1c93848)
1cb7a01acSMauro Carvalho Chehab /*
2cb7a01acSMauro Carvalho Chehab  * adv7183.c Analog Devices ADV7183 video decoder driver
3cb7a01acSMauro Carvalho Chehab  *
4cb7a01acSMauro Carvalho Chehab  * Copyright (c) 2011 Analog Devices Inc.
5cb7a01acSMauro Carvalho Chehab  *
6cb7a01acSMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or modify
7cb7a01acSMauro Carvalho Chehab  * it under the terms of the GNU General Public License version 2 as
8cb7a01acSMauro Carvalho Chehab  * published by the Free Software Foundation.
9cb7a01acSMauro Carvalho Chehab  *
10cb7a01acSMauro Carvalho Chehab  * This program is distributed in the hope that it will be useful,
11cb7a01acSMauro Carvalho Chehab  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12cb7a01acSMauro Carvalho Chehab  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13cb7a01acSMauro Carvalho Chehab  * GNU General Public License for more details.
14cb7a01acSMauro Carvalho Chehab  *
15cb7a01acSMauro Carvalho Chehab  * You should have received a copy of the GNU General Public License
16cb7a01acSMauro Carvalho Chehab  * along with this program; if not, write to the Free Software
17cb7a01acSMauro Carvalho Chehab  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18cb7a01acSMauro Carvalho Chehab  */
19cb7a01acSMauro Carvalho Chehab 
20cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
21cb7a01acSMauro Carvalho Chehab #include <linux/errno.h>
22cb7a01acSMauro Carvalho Chehab #include <linux/gpio.h>
23cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
24cb7a01acSMauro Carvalho Chehab #include <linux/init.h>
25cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
26cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
27cb7a01acSMauro Carvalho Chehab #include <linux/types.h>
28cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
29cb7a01acSMauro Carvalho Chehab 
30cb7a01acSMauro Carvalho Chehab #include <media/adv7183.h>
31cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
32cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
33cb7a01acSMauro Carvalho Chehab 
34cb7a01acSMauro Carvalho Chehab #include "adv7183_regs.h"
35cb7a01acSMauro Carvalho Chehab 
36cb7a01acSMauro Carvalho Chehab struct adv7183 {
37cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
38cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler hdl;
39cb7a01acSMauro Carvalho Chehab 
40cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std; /* Current set standard */
41cb7a01acSMauro Carvalho Chehab 	u32 input;
42cb7a01acSMauro Carvalho Chehab 	u32 output;
43cb7a01acSMauro Carvalho Chehab 	unsigned reset_pin;
44cb7a01acSMauro Carvalho Chehab 	unsigned oe_pin;
45cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt fmt;
46cb7a01acSMauro Carvalho Chehab };
47cb7a01acSMauro Carvalho Chehab 
48cb7a01acSMauro Carvalho Chehab /* EXAMPLES USING 27 MHz CLOCK
49cb7a01acSMauro Carvalho Chehab  * Mode 1 CVBS Input (Composite Video on AIN5)
50cb7a01acSMauro Carvalho Chehab  * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
51cb7a01acSMauro Carvalho Chehab  */
52cb7a01acSMauro Carvalho Chehab static const unsigned char adv7183_init_regs[] = {
53cb7a01acSMauro Carvalho Chehab 	ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
54cb7a01acSMauro Carvalho Chehab 	ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
55cb7a01acSMauro Carvalho Chehab 	ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
56cb7a01acSMauro Carvalho Chehab 	ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
57cb7a01acSMauro Carvalho Chehab 	ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
58cb7a01acSMauro Carvalho Chehab 	/* ADI recommended programming sequence */
59cb7a01acSMauro Carvalho Chehab 	ADV7183_ADI_CTRL, 0x80,
60cb7a01acSMauro Carvalho Chehab 	ADV7183_CTI_DNR_CTRL_4, 0x20,
61cb7a01acSMauro Carvalho Chehab 	0x52, 0x18,
62cb7a01acSMauro Carvalho Chehab 	0x58, 0xED,
63cb7a01acSMauro Carvalho Chehab 	0x77, 0xC5,
64cb7a01acSMauro Carvalho Chehab 	0x7C, 0x93,
65cb7a01acSMauro Carvalho Chehab 	0x7D, 0x00,
66cb7a01acSMauro Carvalho Chehab 	0xD0, 0x48,
67cb7a01acSMauro Carvalho Chehab 	0xD5, 0xA0,
68cb7a01acSMauro Carvalho Chehab 	0xD7, 0xEA,
69cb7a01acSMauro Carvalho Chehab 	ADV7183_SD_SATURATION_CR, 0x3E,
70cb7a01acSMauro Carvalho Chehab 	ADV7183_PAL_V_END, 0x3E,
71cb7a01acSMauro Carvalho Chehab 	ADV7183_PAL_F_TOGGLE, 0x0F,
72cb7a01acSMauro Carvalho Chehab 	ADV7183_ADI_CTRL, 0x00,
73cb7a01acSMauro Carvalho Chehab };
74cb7a01acSMauro Carvalho Chehab 
75cb7a01acSMauro Carvalho Chehab static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
76cb7a01acSMauro Carvalho Chehab {
77cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct adv7183, sd);
78cb7a01acSMauro Carvalho Chehab }
79cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
80cb7a01acSMauro Carvalho Chehab {
81cb7a01acSMauro Carvalho Chehab 	return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
82cb7a01acSMauro Carvalho Chehab }
83cb7a01acSMauro Carvalho Chehab 
84cb7a01acSMauro Carvalho Chehab static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
85cb7a01acSMauro Carvalho Chehab {
86cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
87cb7a01acSMauro Carvalho Chehab 
88cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_read_byte_data(client, reg);
89cb7a01acSMauro Carvalho Chehab }
90cb7a01acSMauro Carvalho Chehab 
91cb7a01acSMauro Carvalho Chehab static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
92cb7a01acSMauro Carvalho Chehab 				unsigned char value)
93cb7a01acSMauro Carvalho Chehab {
94cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
95cb7a01acSMauro Carvalho Chehab 
96cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_write_byte_data(client, reg, value);
97cb7a01acSMauro Carvalho Chehab }
98cb7a01acSMauro Carvalho Chehab 
99cb7a01acSMauro Carvalho Chehab static int adv7183_writeregs(struct v4l2_subdev *sd,
100cb7a01acSMauro Carvalho Chehab 		const unsigned char *regs, unsigned int num)
101cb7a01acSMauro Carvalho Chehab {
102cb7a01acSMauro Carvalho Chehab 	unsigned char reg, data;
103cb7a01acSMauro Carvalho Chehab 	unsigned int cnt = 0;
104cb7a01acSMauro Carvalho Chehab 
105cb7a01acSMauro Carvalho Chehab 	if (num & 0x1) {
106cb7a01acSMauro Carvalho Chehab 		v4l2_err(sd, "invalid regs array\n");
107cb7a01acSMauro Carvalho Chehab 		return -1;
108cb7a01acSMauro Carvalho Chehab 	}
109cb7a01acSMauro Carvalho Chehab 
110cb7a01acSMauro Carvalho Chehab 	while (cnt < num) {
111cb7a01acSMauro Carvalho Chehab 		reg = *regs++;
112cb7a01acSMauro Carvalho Chehab 		data = *regs++;
113cb7a01acSMauro Carvalho Chehab 		cnt += 2;
114cb7a01acSMauro Carvalho Chehab 
115cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, reg, data);
116cb7a01acSMauro Carvalho Chehab 	}
117cb7a01acSMauro Carvalho Chehab 	return 0;
118cb7a01acSMauro Carvalho Chehab }
119cb7a01acSMauro Carvalho Chehab 
120cb7a01acSMauro Carvalho Chehab static int adv7183_log_status(struct v4l2_subdev *sd)
121cb7a01acSMauro Carvalho Chehab {
122cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
123cb7a01acSMauro Carvalho Chehab 
124cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
125cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_IN_CTRL));
126cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
127cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VD_SEL));
128cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
129cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_OUT_CTRL));
130cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
131cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
132cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
133cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_AUTO_DET_EN));
134cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
135cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CONTRAST));
136cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
137cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_BRIGHTNESS));
138cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
139cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HUE));
140cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
141cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DEF_Y));
142cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
143cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DEF_C));
144cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
145cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADI_CTRL));
146cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
147cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_POW_MANAGE));
148cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
149cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_1),
150cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_2),
151cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_3));
152cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
153cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_IDENT));
154cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
155cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
156cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
157cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
158cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
159cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
160cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
161cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
162cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
163cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
164cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADI_CTRL_2));
165cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
166cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
167cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
168cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
169cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
170cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
171cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
172cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
173cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
174cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
175cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
176cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
177cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
178cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
179cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
180cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
1816d3be300SMasanari Iida 	v4l2_info(sd, "adv7183: Hsync position control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
182cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
183cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
184cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
185cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
186cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_POLARITY));
187cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
188cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADC_CTRL));
189cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
190cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_OFFSET_CB),
191cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_OFFSET_CR));
192cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
193cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_SATURATION_CB),
194cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_SATURATION_CR));
195cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
196cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DRIVE_STR));
197cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
198cb7a01acSMauro Carvalho Chehab 	return 0;
199cb7a01acSMauro Carvalho Chehab }
200cb7a01acSMauro Carvalho Chehab 
201cb7a01acSMauro Carvalho Chehab static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
202cb7a01acSMauro Carvalho Chehab {
203cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
204cb7a01acSMauro Carvalho Chehab 
205cb7a01acSMauro Carvalho Chehab 	*std = decoder->std;
206cb7a01acSMauro Carvalho Chehab 	return 0;
207cb7a01acSMauro Carvalho Chehab }
208cb7a01acSMauro Carvalho Chehab 
209cb7a01acSMauro Carvalho Chehab static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
210cb7a01acSMauro Carvalho Chehab {
211cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
212cb7a01acSMauro Carvalho Chehab 	int reg;
213cb7a01acSMauro Carvalho Chehab 
214cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
215cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_PAL_60)
216cb7a01acSMauro Carvalho Chehab 		reg |= 0x60;
217cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_NTSC_443)
218cb7a01acSMauro Carvalho Chehab 		reg |= 0x70;
219cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_N)
220cb7a01acSMauro Carvalho Chehab 		reg |= 0x90;
221cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_M)
222cb7a01acSMauro Carvalho Chehab 		reg |= 0xA0;
223cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_Nc)
224cb7a01acSMauro Carvalho Chehab 		reg |= 0xC0;
225cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_PAL)
226cb7a01acSMauro Carvalho Chehab 		reg |= 0x80;
227cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_NTSC)
228cb7a01acSMauro Carvalho Chehab 		reg |= 0x50;
229cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_SECAM)
230cb7a01acSMauro Carvalho Chehab 		reg |= 0xE0;
231cb7a01acSMauro Carvalho Chehab 	else
232cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
233cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
234cb7a01acSMauro Carvalho Chehab 
235cb7a01acSMauro Carvalho Chehab 	decoder->std = std;
236cb7a01acSMauro Carvalho Chehab 
237cb7a01acSMauro Carvalho Chehab 	return 0;
238cb7a01acSMauro Carvalho Chehab }
239cb7a01acSMauro Carvalho Chehab 
240cb7a01acSMauro Carvalho Chehab static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
241cb7a01acSMauro Carvalho Chehab {
242cb7a01acSMauro Carvalho Chehab 	int reg;
243cb7a01acSMauro Carvalho Chehab 
244cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
245cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_POW_MANAGE, reg);
246cb7a01acSMauro Carvalho Chehab 	/* wait 5ms before any further i2c writes are performed */
247cb7a01acSMauro Carvalho Chehab 	usleep_range(5000, 10000);
248cb7a01acSMauro Carvalho Chehab 	return 0;
249cb7a01acSMauro Carvalho Chehab }
250cb7a01acSMauro Carvalho Chehab 
251cb7a01acSMauro Carvalho Chehab static int adv7183_s_routing(struct v4l2_subdev *sd,
252cb7a01acSMauro Carvalho Chehab 				u32 input, u32 output, u32 config)
253cb7a01acSMauro Carvalho Chehab {
254cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
255cb7a01acSMauro Carvalho Chehab 	int reg;
256cb7a01acSMauro Carvalho Chehab 
257cb7a01acSMauro Carvalho Chehab 	if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
258cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
259cb7a01acSMauro Carvalho Chehab 
260cb7a01acSMauro Carvalho Chehab 	if (input != decoder->input) {
261cb7a01acSMauro Carvalho Chehab 		decoder->input = input;
262cb7a01acSMauro Carvalho Chehab 		reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
263cb7a01acSMauro Carvalho Chehab 		switch (input) {
264cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE1:
265cb7a01acSMauro Carvalho Chehab 			reg |= 0x1;
266cb7a01acSMauro Carvalho Chehab 			break;
267cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE2:
268cb7a01acSMauro Carvalho Chehab 			reg |= 0x2;
269cb7a01acSMauro Carvalho Chehab 			break;
270cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE3:
271cb7a01acSMauro Carvalho Chehab 			reg |= 0x3;
272cb7a01acSMauro Carvalho Chehab 			break;
273cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE4:
274cb7a01acSMauro Carvalho Chehab 			reg |= 0x4;
275cb7a01acSMauro Carvalho Chehab 			break;
276cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE5:
277cb7a01acSMauro Carvalho Chehab 			reg |= 0x5;
278cb7a01acSMauro Carvalho Chehab 			break;
279cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE6:
280cb7a01acSMauro Carvalho Chehab 			reg |= 0xB;
281cb7a01acSMauro Carvalho Chehab 			break;
282cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE7:
283cb7a01acSMauro Carvalho Chehab 			reg |= 0xC;
284cb7a01acSMauro Carvalho Chehab 			break;
285cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE8:
286cb7a01acSMauro Carvalho Chehab 			reg |= 0xD;
287cb7a01acSMauro Carvalho Chehab 			break;
288cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE9:
289cb7a01acSMauro Carvalho Chehab 			reg |= 0xE;
290cb7a01acSMauro Carvalho Chehab 			break;
291cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE10:
292cb7a01acSMauro Carvalho Chehab 			reg |= 0xF;
293cb7a01acSMauro Carvalho Chehab 			break;
294cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO0:
295cb7a01acSMauro Carvalho Chehab 			reg |= 0x6;
296cb7a01acSMauro Carvalho Chehab 			break;
297cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO1:
298cb7a01acSMauro Carvalho Chehab 			reg |= 0x7;
299cb7a01acSMauro Carvalho Chehab 			break;
300cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO2:
301cb7a01acSMauro Carvalho Chehab 			reg |= 0x8;
302cb7a01acSMauro Carvalho Chehab 			break;
303cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPONENT0:
304cb7a01acSMauro Carvalho Chehab 			reg |= 0x9;
305cb7a01acSMauro Carvalho Chehab 			break;
306cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPONENT1:
307cb7a01acSMauro Carvalho Chehab 			reg |= 0xA;
308cb7a01acSMauro Carvalho Chehab 			break;
309cb7a01acSMauro Carvalho Chehab 		default:
310cb7a01acSMauro Carvalho Chehab 			break;
311cb7a01acSMauro Carvalho Chehab 		}
312cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_IN_CTRL, reg);
313cb7a01acSMauro Carvalho Chehab 	}
314cb7a01acSMauro Carvalho Chehab 
315cb7a01acSMauro Carvalho Chehab 	if (output != decoder->output) {
316cb7a01acSMauro Carvalho Chehab 		decoder->output = output;
317cb7a01acSMauro Carvalho Chehab 		reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
318cb7a01acSMauro Carvalho Chehab 		switch (output) {
319cb7a01acSMauro Carvalho Chehab 		case ADV7183_16BIT_OUT:
320cb7a01acSMauro Carvalho Chehab 			reg |= 0x9;
321cb7a01acSMauro Carvalho Chehab 			break;
322cb7a01acSMauro Carvalho Chehab 		default:
323cb7a01acSMauro Carvalho Chehab 			reg |= 0xC;
324cb7a01acSMauro Carvalho Chehab 			break;
325cb7a01acSMauro Carvalho Chehab 		}
326cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_OUT_CTRL, reg);
327cb7a01acSMauro Carvalho Chehab 	}
328cb7a01acSMauro Carvalho Chehab 
329cb7a01acSMauro Carvalho Chehab 	return 0;
330cb7a01acSMauro Carvalho Chehab }
331cb7a01acSMauro Carvalho Chehab 
332cb7a01acSMauro Carvalho Chehab static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
333cb7a01acSMauro Carvalho Chehab {
334cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
335cb7a01acSMauro Carvalho Chehab 	int val = ctrl->val;
336cb7a01acSMauro Carvalho Chehab 
337cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
338cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
339cb7a01acSMauro Carvalho Chehab 		if (val < 0)
340cb7a01acSMauro Carvalho Chehab 			val = 127 - val;
341cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_BRIGHTNESS, val);
342cb7a01acSMauro Carvalho Chehab 		break;
343cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
344cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_CONTRAST, val);
345cb7a01acSMauro Carvalho Chehab 		break;
346cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
347cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
348cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
349cb7a01acSMauro Carvalho Chehab 		break;
350cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
351cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
352cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
353cb7a01acSMauro Carvalho Chehab 		break;
354cb7a01acSMauro Carvalho Chehab 	default:
355cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
356cb7a01acSMauro Carvalho Chehab 	}
357cb7a01acSMauro Carvalho Chehab 
358cb7a01acSMauro Carvalho Chehab 	return 0;
359cb7a01acSMauro Carvalho Chehab }
360cb7a01acSMauro Carvalho Chehab 
361cb7a01acSMauro Carvalho Chehab static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
362cb7a01acSMauro Carvalho Chehab {
363cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
364cb7a01acSMauro Carvalho Chehab 	int reg;
365cb7a01acSMauro Carvalho Chehab 
366cb7a01acSMauro Carvalho Chehab 	/* enable autodetection block */
367cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
368cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
369cb7a01acSMauro Carvalho Chehab 
370cb7a01acSMauro Carvalho Chehab 	/* wait autodetection switch */
371cb7a01acSMauro Carvalho Chehab 	mdelay(10);
372cb7a01acSMauro Carvalho Chehab 
373cb7a01acSMauro Carvalho Chehab 	/* get autodetection result */
374cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_STATUS_1);
375cb7a01acSMauro Carvalho Chehab 	switch ((reg >> 0x4) & 0x7) {
376cb7a01acSMauro Carvalho Chehab 	case 0:
3777dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC;
378cb7a01acSMauro Carvalho Chehab 		break;
379cb7a01acSMauro Carvalho Chehab 	case 1:
3807dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC_443;
381cb7a01acSMauro Carvalho Chehab 		break;
382cb7a01acSMauro Carvalho Chehab 	case 2:
3837dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_M;
384cb7a01acSMauro Carvalho Chehab 		break;
385cb7a01acSMauro Carvalho Chehab 	case 3:
3867dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_60;
387cb7a01acSMauro Carvalho Chehab 		break;
388cb7a01acSMauro Carvalho Chehab 	case 4:
3897dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL;
390cb7a01acSMauro Carvalho Chehab 		break;
391cb7a01acSMauro Carvalho Chehab 	case 5:
3927dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
393cb7a01acSMauro Carvalho Chehab 		break;
394cb7a01acSMauro Carvalho Chehab 	case 6:
3957dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_Nc;
396cb7a01acSMauro Carvalho Chehab 		break;
397cb7a01acSMauro Carvalho Chehab 	case 7:
3987dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
399cb7a01acSMauro Carvalho Chehab 		break;
400cb7a01acSMauro Carvalho Chehab 	default:
401cb7a01acSMauro Carvalho Chehab 		*std = V4L2_STD_UNKNOWN;
402cb7a01acSMauro Carvalho Chehab 		break;
403cb7a01acSMauro Carvalho Chehab 	}
404cb7a01acSMauro Carvalho Chehab 
405cb7a01acSMauro Carvalho Chehab 	/* after std detection, write back user set std */
406cb7a01acSMauro Carvalho Chehab 	adv7183_s_std(sd, decoder->std);
407cb7a01acSMauro Carvalho Chehab 	return 0;
408cb7a01acSMauro Carvalho Chehab }
409cb7a01acSMauro Carvalho Chehab 
410cb7a01acSMauro Carvalho Chehab static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
411cb7a01acSMauro Carvalho Chehab {
412cb7a01acSMauro Carvalho Chehab 	int reg;
413cb7a01acSMauro Carvalho Chehab 
414cb7a01acSMauro Carvalho Chehab 	*status = V4L2_IN_ST_NO_SIGNAL;
415cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_STATUS_1);
416cb7a01acSMauro Carvalho Chehab 	if (reg < 0)
417cb7a01acSMauro Carvalho Chehab 		return reg;
418cb7a01acSMauro Carvalho Chehab 	if (reg & 0x1)
419cb7a01acSMauro Carvalho Chehab 		*status = 0;
420cb7a01acSMauro Carvalho Chehab 	return 0;
421cb7a01acSMauro Carvalho Chehab }
422cb7a01acSMauro Carvalho Chehab 
423*ebcff5fcSHans Verkuil static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
424*ebcff5fcSHans Verkuil 		struct v4l2_subdev_pad_config *cfg,
425*ebcff5fcSHans Verkuil 		struct v4l2_subdev_mbus_code_enum *code)
426cb7a01acSMauro Carvalho Chehab {
427*ebcff5fcSHans Verkuil 	if (code->pad || code->index > 0)
428cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
429cb7a01acSMauro Carvalho Chehab 
430*ebcff5fcSHans Verkuil 	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
431cb7a01acSMauro Carvalho Chehab 	return 0;
432cb7a01acSMauro Carvalho Chehab }
433cb7a01acSMauro Carvalho Chehab 
434cb7a01acSMauro Carvalho Chehab static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
435cb7a01acSMauro Carvalho Chehab 				struct v4l2_mbus_framefmt *fmt)
436cb7a01acSMauro Carvalho Chehab {
437cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
438cb7a01acSMauro Carvalho Chehab 
439f5fe58fdSBoris BREZILLON 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
440cb7a01acSMauro Carvalho Chehab 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
441cb7a01acSMauro Carvalho Chehab 	if (decoder->std & V4L2_STD_525_60) {
442cb7a01acSMauro Carvalho Chehab 		fmt->field = V4L2_FIELD_SEQ_TB;
443cb7a01acSMauro Carvalho Chehab 		fmt->width = 720;
444cb7a01acSMauro Carvalho Chehab 		fmt->height = 480;
445cb7a01acSMauro Carvalho Chehab 	} else {
446cb7a01acSMauro Carvalho Chehab 		fmt->field = V4L2_FIELD_SEQ_BT;
447cb7a01acSMauro Carvalho Chehab 		fmt->width = 720;
448cb7a01acSMauro Carvalho Chehab 		fmt->height = 576;
449cb7a01acSMauro Carvalho Chehab 	}
450cb7a01acSMauro Carvalho Chehab 	return 0;
451cb7a01acSMauro Carvalho Chehab }
452cb7a01acSMauro Carvalho Chehab 
453cb7a01acSMauro Carvalho Chehab static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
454cb7a01acSMauro Carvalho Chehab 				struct v4l2_mbus_framefmt *fmt)
455cb7a01acSMauro Carvalho Chehab {
456cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
457cb7a01acSMauro Carvalho Chehab 
458cb7a01acSMauro Carvalho Chehab 	adv7183_try_mbus_fmt(sd, fmt);
459cb7a01acSMauro Carvalho Chehab 	decoder->fmt = *fmt;
460cb7a01acSMauro Carvalho Chehab 	return 0;
461cb7a01acSMauro Carvalho Chehab }
462cb7a01acSMauro Carvalho Chehab 
463cb7a01acSMauro Carvalho Chehab static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
464cb7a01acSMauro Carvalho Chehab 				struct v4l2_mbus_framefmt *fmt)
465cb7a01acSMauro Carvalho Chehab {
466cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
467cb7a01acSMauro Carvalho Chehab 
468cb7a01acSMauro Carvalho Chehab 	*fmt = decoder->fmt;
469cb7a01acSMauro Carvalho Chehab 	return 0;
470cb7a01acSMauro Carvalho Chehab }
471cb7a01acSMauro Carvalho Chehab 
472cb7a01acSMauro Carvalho Chehab static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
473cb7a01acSMauro Carvalho Chehab {
474cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
475cb7a01acSMauro Carvalho Chehab 
476cb7a01acSMauro Carvalho Chehab 	if (enable)
47795323361SLaurent Pinchart 		gpio_set_value(decoder->oe_pin, 0);
478cb7a01acSMauro Carvalho Chehab 	else
47995323361SLaurent Pinchart 		gpio_set_value(decoder->oe_pin, 1);
480cb7a01acSMauro Carvalho Chehab 	udelay(1);
481cb7a01acSMauro Carvalho Chehab 	return 0;
482cb7a01acSMauro Carvalho Chehab }
483cb7a01acSMauro Carvalho Chehab 
484cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
485cb7a01acSMauro Carvalho Chehab static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
486cb7a01acSMauro Carvalho Chehab {
487cb7a01acSMauro Carvalho Chehab 	reg->val = adv7183_read(sd, reg->reg & 0xff);
488cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
489cb7a01acSMauro Carvalho Chehab 	return 0;
490cb7a01acSMauro Carvalho Chehab }
491cb7a01acSMauro Carvalho Chehab 
492977ba3b1SHans Verkuil static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
493cb7a01acSMauro Carvalho Chehab {
494cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
495cb7a01acSMauro Carvalho Chehab 	return 0;
496cb7a01acSMauro Carvalho Chehab }
497cb7a01acSMauro Carvalho Chehab #endif
498cb7a01acSMauro Carvalho Chehab 
499cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
500cb7a01acSMauro Carvalho Chehab 	.s_ctrl = adv7183_s_ctrl,
501cb7a01acSMauro Carvalho Chehab };
502cb7a01acSMauro Carvalho Chehab 
503cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7183_core_ops = {
504cb7a01acSMauro Carvalho Chehab 	.log_status = adv7183_log_status,
505cb7a01acSMauro Carvalho Chehab 	.reset = adv7183_reset,
506cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
507cb7a01acSMauro Carvalho Chehab 	.g_register = adv7183_g_register,
508cb7a01acSMauro Carvalho Chehab 	.s_register = adv7183_s_register,
509cb7a01acSMauro Carvalho Chehab #endif
510cb7a01acSMauro Carvalho Chehab };
511cb7a01acSMauro Carvalho Chehab 
512cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7183_video_ops = {
5138774bed9SLaurent Pinchart 	.g_std = adv7183_g_std,
5148774bed9SLaurent Pinchart 	.s_std = adv7183_s_std,
515cb7a01acSMauro Carvalho Chehab 	.s_routing = adv7183_s_routing,
516cb7a01acSMauro Carvalho Chehab 	.querystd = adv7183_querystd,
517cb7a01acSMauro Carvalho Chehab 	.g_input_status = adv7183_g_input_status,
518cb7a01acSMauro Carvalho Chehab 	.try_mbus_fmt = adv7183_try_mbus_fmt,
519cb7a01acSMauro Carvalho Chehab 	.s_mbus_fmt = adv7183_s_mbus_fmt,
520cb7a01acSMauro Carvalho Chehab 	.g_mbus_fmt = adv7183_g_mbus_fmt,
521cb7a01acSMauro Carvalho Chehab 	.s_stream = adv7183_s_stream,
522cb7a01acSMauro Carvalho Chehab };
523cb7a01acSMauro Carvalho Chehab 
524*ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops adv7183_pad_ops = {
525*ebcff5fcSHans Verkuil 	.enum_mbus_code = adv7183_enum_mbus_code,
526*ebcff5fcSHans Verkuil };
527*ebcff5fcSHans Verkuil 
528cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7183_ops = {
529cb7a01acSMauro Carvalho Chehab 	.core = &adv7183_core_ops,
530cb7a01acSMauro Carvalho Chehab 	.video = &adv7183_video_ops,
531*ebcff5fcSHans Verkuil 	.pad = &adv7183_pad_ops,
532cb7a01acSMauro Carvalho Chehab };
533cb7a01acSMauro Carvalho Chehab 
534cb7a01acSMauro Carvalho Chehab static int adv7183_probe(struct i2c_client *client,
535cb7a01acSMauro Carvalho Chehab 			const struct i2c_device_id *id)
536cb7a01acSMauro Carvalho Chehab {
537cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder;
538cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
539cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler *hdl;
540cb7a01acSMauro Carvalho Chehab 	int ret;
541cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt fmt;
542cb7a01acSMauro Carvalho Chehab 	const unsigned *pin_array;
543cb7a01acSMauro Carvalho Chehab 
544cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
545cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
546cb7a01acSMauro Carvalho Chehab 		return -EIO;
547cb7a01acSMauro Carvalho Chehab 
548cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
549cb7a01acSMauro Carvalho Chehab 			client->addr << 1, client->adapter->name);
550cb7a01acSMauro Carvalho Chehab 
551cb7a01acSMauro Carvalho Chehab 	pin_array = client->dev.platform_data;
552cb7a01acSMauro Carvalho Chehab 	if (pin_array == NULL)
553cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
554cb7a01acSMauro Carvalho Chehab 
555c02b211dSLaurent Pinchart 	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
556cb7a01acSMauro Carvalho Chehab 	if (decoder == NULL)
557cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
558cb7a01acSMauro Carvalho Chehab 
559cb7a01acSMauro Carvalho Chehab 	decoder->reset_pin = pin_array[0];
560cb7a01acSMauro Carvalho Chehab 	decoder->oe_pin = pin_array[1];
561cb7a01acSMauro Carvalho Chehab 
562b015ba29SLaurent Pinchart 	if (devm_gpio_request_one(&client->dev, decoder->reset_pin,
563b015ba29SLaurent Pinchart 				  GPIOF_OUT_INIT_LOW, "ADV7183 Reset")) {
564cb7a01acSMauro Carvalho Chehab 		v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
565c02b211dSLaurent Pinchart 		return -EBUSY;
566cb7a01acSMauro Carvalho Chehab 	}
567cb7a01acSMauro Carvalho Chehab 
568b015ba29SLaurent Pinchart 	if (devm_gpio_request_one(&client->dev, decoder->oe_pin,
569b015ba29SLaurent Pinchart 				  GPIOF_OUT_INIT_HIGH,
57095323361SLaurent Pinchart 				  "ADV7183 Output Enable")) {
571cb7a01acSMauro Carvalho Chehab 		v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
572b015ba29SLaurent Pinchart 		return -EBUSY;
573cb7a01acSMauro Carvalho Chehab 	}
574cb7a01acSMauro Carvalho Chehab 
575cb7a01acSMauro Carvalho Chehab 	sd = &decoder->sd;
576cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
577cb7a01acSMauro Carvalho Chehab 
578cb7a01acSMauro Carvalho Chehab 	hdl = &decoder->hdl;
579cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(hdl, 4);
580cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
581cb7a01acSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
582cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
583cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
584cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
585cb7a01acSMauro Carvalho Chehab 			V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
586cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
587cb7a01acSMauro Carvalho Chehab 			V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
588cb7a01acSMauro Carvalho Chehab 	/* hook the control handler into the driver */
589cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = hdl;
590cb7a01acSMauro Carvalho Chehab 	if (hdl->error) {
591cb7a01acSMauro Carvalho Chehab 		ret = hdl->error;
592cb7a01acSMauro Carvalho Chehab 
593cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(hdl);
594b015ba29SLaurent Pinchart 		return ret;
595cb7a01acSMauro Carvalho Chehab 	}
596cb7a01acSMauro Carvalho Chehab 
597cb7a01acSMauro Carvalho Chehab 	/* v4l2 doesn't support an autodetect standard, pick PAL as default */
598cb7a01acSMauro Carvalho Chehab 	decoder->std = V4L2_STD_PAL;
599cb7a01acSMauro Carvalho Chehab 	decoder->input = ADV7183_COMPOSITE4;
600cb7a01acSMauro Carvalho Chehab 	decoder->output = ADV7183_8BIT_OUT;
601cb7a01acSMauro Carvalho Chehab 
602cb7a01acSMauro Carvalho Chehab 	/* reset chip */
603cb7a01acSMauro Carvalho Chehab 	/* reset pulse width at least 5ms */
604cb7a01acSMauro Carvalho Chehab 	mdelay(10);
60595323361SLaurent Pinchart 	gpio_set_value(decoder->reset_pin, 1);
606cb7a01acSMauro Carvalho Chehab 	/* wait 5ms before any further i2c writes are performed */
607cb7a01acSMauro Carvalho Chehab 	mdelay(5);
608cb7a01acSMauro Carvalho Chehab 
609cb7a01acSMauro Carvalho Chehab 	adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
610cb7a01acSMauro Carvalho Chehab 	adv7183_s_std(sd, decoder->std);
611cb7a01acSMauro Carvalho Chehab 	fmt.width = 720;
612cb7a01acSMauro Carvalho Chehab 	fmt.height = 576;
613cb7a01acSMauro Carvalho Chehab 	adv7183_s_mbus_fmt(sd, &fmt);
614cb7a01acSMauro Carvalho Chehab 
615cb7a01acSMauro Carvalho Chehab 	/* initialize the hardware to the default control values */
616cb7a01acSMauro Carvalho Chehab 	ret = v4l2_ctrl_handler_setup(hdl);
617cb7a01acSMauro Carvalho Chehab 	if (ret) {
618cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(hdl);
619b015ba29SLaurent Pinchart 		return ret;
620cb7a01acSMauro Carvalho Chehab 	}
621cb7a01acSMauro Carvalho Chehab 
622cb7a01acSMauro Carvalho Chehab 	return 0;
623cb7a01acSMauro Carvalho Chehab }
624cb7a01acSMauro Carvalho Chehab 
625cb7a01acSMauro Carvalho Chehab static int adv7183_remove(struct i2c_client *client)
626cb7a01acSMauro Carvalho Chehab {
627cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
628cb7a01acSMauro Carvalho Chehab 
629cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
630cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(sd->ctrl_handler);
631cb7a01acSMauro Carvalho Chehab 	return 0;
632cb7a01acSMauro Carvalho Chehab }
633cb7a01acSMauro Carvalho Chehab 
634cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7183_id[] = {
635cb7a01acSMauro Carvalho Chehab 	{"adv7183", 0},
636cb7a01acSMauro Carvalho Chehab 	{},
637cb7a01acSMauro Carvalho Chehab };
638cb7a01acSMauro Carvalho Chehab 
639cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, adv7183_id);
640cb7a01acSMauro Carvalho Chehab 
641cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7183_driver = {
642cb7a01acSMauro Carvalho Chehab 	.driver = {
643cb7a01acSMauro Carvalho Chehab 		.owner  = THIS_MODULE,
644cb7a01acSMauro Carvalho Chehab 		.name   = "adv7183",
645cb7a01acSMauro Carvalho Chehab 	},
646cb7a01acSMauro Carvalho Chehab 	.probe          = adv7183_probe,
6474c62e976SGreg Kroah-Hartman 	.remove         = adv7183_remove,
648cb7a01acSMauro Carvalho Chehab 	.id_table       = adv7183_id,
649cb7a01acSMauro Carvalho Chehab };
650cb7a01acSMauro Carvalho Chehab 
65101aea0bfSWei Yongjun module_i2c_driver(adv7183_driver);
652cb7a01acSMauro Carvalho Chehab 
653cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
654cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
655cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
656