xref: /openbmc/linux/drivers/media/i2c/adv7183.c (revision aaeb31c0)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2cb7a01acSMauro Carvalho Chehab /*
3cb7a01acSMauro Carvalho Chehab  * adv7183.c Analog Devices ADV7183 video decoder driver
4cb7a01acSMauro Carvalho Chehab  *
5cb7a01acSMauro Carvalho Chehab  * Copyright (c) 2011 Analog Devices Inc.
6cb7a01acSMauro Carvalho Chehab  */
7cb7a01acSMauro Carvalho Chehab 
8cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
9cb7a01acSMauro Carvalho Chehab #include <linux/errno.h>
103e4fcec0SLinus Walleij #include <linux/gpio/consumer.h>
11cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
12cb7a01acSMauro Carvalho Chehab #include <linux/init.h>
13cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
14cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
15cb7a01acSMauro Carvalho Chehab #include <linux/types.h>
16cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
17cb7a01acSMauro Carvalho Chehab 
18b5dcee22SMauro Carvalho Chehab #include <media/i2c/adv7183.h>
19cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h>
20cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
21cb7a01acSMauro Carvalho Chehab 
22cb7a01acSMauro Carvalho Chehab #include "adv7183_regs.h"
23cb7a01acSMauro Carvalho Chehab 
24cb7a01acSMauro Carvalho Chehab struct adv7183 {
25cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
26cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler hdl;
27cb7a01acSMauro Carvalho Chehab 
28cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std; /* Current set standard */
29cb7a01acSMauro Carvalho Chehab 	u32 input;
30cb7a01acSMauro Carvalho Chehab 	u32 output;
313e4fcec0SLinus Walleij 	struct gpio_desc *reset_pin;
323e4fcec0SLinus Walleij 	struct gpio_desc *oe_pin;
33cb7a01acSMauro Carvalho Chehab 	struct v4l2_mbus_framefmt fmt;
34cb7a01acSMauro Carvalho Chehab };
35cb7a01acSMauro Carvalho Chehab 
36cb7a01acSMauro Carvalho Chehab /* EXAMPLES USING 27 MHz CLOCK
37cb7a01acSMauro Carvalho Chehab  * Mode 1 CVBS Input (Composite Video on AIN5)
38cb7a01acSMauro Carvalho Chehab  * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
39cb7a01acSMauro Carvalho Chehab  */
40cb7a01acSMauro Carvalho Chehab static const unsigned char adv7183_init_regs[] = {
41cb7a01acSMauro Carvalho Chehab 	ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
42cb7a01acSMauro Carvalho Chehab 	ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
43cb7a01acSMauro Carvalho Chehab 	ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
44cb7a01acSMauro Carvalho Chehab 	ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
45cb7a01acSMauro Carvalho Chehab 	ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
46cb7a01acSMauro Carvalho Chehab 	/* ADI recommended programming sequence */
47cb7a01acSMauro Carvalho Chehab 	ADV7183_ADI_CTRL, 0x80,
48cb7a01acSMauro Carvalho Chehab 	ADV7183_CTI_DNR_CTRL_4, 0x20,
49cb7a01acSMauro Carvalho Chehab 	0x52, 0x18,
50cb7a01acSMauro Carvalho Chehab 	0x58, 0xED,
51cb7a01acSMauro Carvalho Chehab 	0x77, 0xC5,
52cb7a01acSMauro Carvalho Chehab 	0x7C, 0x93,
53cb7a01acSMauro Carvalho Chehab 	0x7D, 0x00,
54cb7a01acSMauro Carvalho Chehab 	0xD0, 0x48,
55cb7a01acSMauro Carvalho Chehab 	0xD5, 0xA0,
56cb7a01acSMauro Carvalho Chehab 	0xD7, 0xEA,
57cb7a01acSMauro Carvalho Chehab 	ADV7183_SD_SATURATION_CR, 0x3E,
58cb7a01acSMauro Carvalho Chehab 	ADV7183_PAL_V_END, 0x3E,
59cb7a01acSMauro Carvalho Chehab 	ADV7183_PAL_F_TOGGLE, 0x0F,
60cb7a01acSMauro Carvalho Chehab 	ADV7183_ADI_CTRL, 0x00,
61cb7a01acSMauro Carvalho Chehab };
62cb7a01acSMauro Carvalho Chehab 
to_adv7183(struct v4l2_subdev * sd)63cb7a01acSMauro Carvalho Chehab static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
64cb7a01acSMauro Carvalho Chehab {
65cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct adv7183, sd);
66cb7a01acSMauro Carvalho Chehab }
to_sd(struct v4l2_ctrl * ctrl)67cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
68cb7a01acSMauro Carvalho Chehab {
69cb7a01acSMauro Carvalho Chehab 	return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
70cb7a01acSMauro Carvalho Chehab }
71cb7a01acSMauro Carvalho Chehab 
adv7183_read(struct v4l2_subdev * sd,unsigned char reg)72cb7a01acSMauro Carvalho Chehab static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
73cb7a01acSMauro Carvalho Chehab {
74cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
75cb7a01acSMauro Carvalho Chehab 
76cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_read_byte_data(client, reg);
77cb7a01acSMauro Carvalho Chehab }
78cb7a01acSMauro Carvalho Chehab 
adv7183_write(struct v4l2_subdev * sd,unsigned char reg,unsigned char value)79cb7a01acSMauro Carvalho Chehab static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
80cb7a01acSMauro Carvalho Chehab 				unsigned char value)
81cb7a01acSMauro Carvalho Chehab {
82cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
83cb7a01acSMauro Carvalho Chehab 
84cb7a01acSMauro Carvalho Chehab 	return i2c_smbus_write_byte_data(client, reg, value);
85cb7a01acSMauro Carvalho Chehab }
86cb7a01acSMauro Carvalho Chehab 
adv7183_writeregs(struct v4l2_subdev * sd,const unsigned char * regs,unsigned int num)87cb7a01acSMauro Carvalho Chehab static int adv7183_writeregs(struct v4l2_subdev *sd,
88cb7a01acSMauro Carvalho Chehab 		const unsigned char *regs, unsigned int num)
89cb7a01acSMauro Carvalho Chehab {
90cb7a01acSMauro Carvalho Chehab 	unsigned char reg, data;
91cb7a01acSMauro Carvalho Chehab 	unsigned int cnt = 0;
92cb7a01acSMauro Carvalho Chehab 
93cb7a01acSMauro Carvalho Chehab 	if (num & 0x1) {
94cb7a01acSMauro Carvalho Chehab 		v4l2_err(sd, "invalid regs array\n");
95cb7a01acSMauro Carvalho Chehab 		return -1;
96cb7a01acSMauro Carvalho Chehab 	}
97cb7a01acSMauro Carvalho Chehab 
98cb7a01acSMauro Carvalho Chehab 	while (cnt < num) {
99cb7a01acSMauro Carvalho Chehab 		reg = *regs++;
100cb7a01acSMauro Carvalho Chehab 		data = *regs++;
101cb7a01acSMauro Carvalho Chehab 		cnt += 2;
102cb7a01acSMauro Carvalho Chehab 
103cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, reg, data);
104cb7a01acSMauro Carvalho Chehab 	}
105cb7a01acSMauro Carvalho Chehab 	return 0;
106cb7a01acSMauro Carvalho Chehab }
107cb7a01acSMauro Carvalho Chehab 
adv7183_log_status(struct v4l2_subdev * sd)108cb7a01acSMauro Carvalho Chehab static int adv7183_log_status(struct v4l2_subdev *sd)
109cb7a01acSMauro Carvalho Chehab {
110cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
111cb7a01acSMauro Carvalho Chehab 
112cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
113cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_IN_CTRL));
114cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
115cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VD_SEL));
116cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
117cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_OUT_CTRL));
118cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
119cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
120cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
121cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_AUTO_DET_EN));
122cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
123cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CONTRAST));
124cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
125cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_BRIGHTNESS));
126cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
127cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HUE));
128cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
129cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DEF_Y));
130cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
131cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DEF_C));
132cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
133cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADI_CTRL));
134cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
135cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_POW_MANAGE));
136cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
137cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_1),
138cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_2),
139cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_STATUS_3));
140cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
141cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_IDENT));
142cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
143cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
144cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
145cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
146cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
147cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
148cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
149cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
150cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
151cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
152cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADI_CTRL_2));
153cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
154cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
155cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
156cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
157cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
158cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
159cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
160cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
161cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
162cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
163cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
164cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
165cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
166cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
167cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
168cb7a01acSMauro Carvalho Chehab 			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",
170cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
171cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
172cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
173cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
174cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_POLARITY));
175cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
176cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_ADC_CTRL));
177cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
178cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_OFFSET_CB),
179cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_OFFSET_CR));
180cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
181cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_SATURATION_CB),
182cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_SD_SATURATION_CR));
183cb7a01acSMauro Carvalho Chehab 	v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
184cb7a01acSMauro Carvalho Chehab 			adv7183_read(sd, ADV7183_DRIVE_STR));
185cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
186cb7a01acSMauro Carvalho Chehab 	return 0;
187cb7a01acSMauro Carvalho Chehab }
188cb7a01acSMauro Carvalho Chehab 
adv7183_g_std(struct v4l2_subdev * sd,v4l2_std_id * std)189cb7a01acSMauro Carvalho Chehab static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
190cb7a01acSMauro Carvalho Chehab {
191cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
192cb7a01acSMauro Carvalho Chehab 
193cb7a01acSMauro Carvalho Chehab 	*std = decoder->std;
194cb7a01acSMauro Carvalho Chehab 	return 0;
195cb7a01acSMauro Carvalho Chehab }
196cb7a01acSMauro Carvalho Chehab 
adv7183_s_std(struct v4l2_subdev * sd,v4l2_std_id std)197cb7a01acSMauro Carvalho Chehab static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
198cb7a01acSMauro Carvalho Chehab {
199cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
200cb7a01acSMauro Carvalho Chehab 	int reg;
201cb7a01acSMauro Carvalho Chehab 
202cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
203cb7a01acSMauro Carvalho Chehab 	if (std == V4L2_STD_PAL_60)
204cb7a01acSMauro Carvalho Chehab 		reg |= 0x60;
205cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_NTSC_443)
206cb7a01acSMauro Carvalho Chehab 		reg |= 0x70;
207cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_N)
208cb7a01acSMauro Carvalho Chehab 		reg |= 0x90;
209cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_M)
210cb7a01acSMauro Carvalho Chehab 		reg |= 0xA0;
211cb7a01acSMauro Carvalho Chehab 	else if (std == V4L2_STD_PAL_Nc)
212cb7a01acSMauro Carvalho Chehab 		reg |= 0xC0;
213cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_PAL)
214cb7a01acSMauro Carvalho Chehab 		reg |= 0x80;
215cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_NTSC)
216cb7a01acSMauro Carvalho Chehab 		reg |= 0x50;
217cb7a01acSMauro Carvalho Chehab 	else if (std & V4L2_STD_SECAM)
218cb7a01acSMauro Carvalho Chehab 		reg |= 0xE0;
219cb7a01acSMauro Carvalho Chehab 	else
220cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
221cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
222cb7a01acSMauro Carvalho Chehab 
223cb7a01acSMauro Carvalho Chehab 	decoder->std = std;
224cb7a01acSMauro Carvalho Chehab 
225cb7a01acSMauro Carvalho Chehab 	return 0;
226cb7a01acSMauro Carvalho Chehab }
227cb7a01acSMauro Carvalho Chehab 
adv7183_reset(struct v4l2_subdev * sd,u32 val)228cb7a01acSMauro Carvalho Chehab static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
229cb7a01acSMauro Carvalho Chehab {
230cb7a01acSMauro Carvalho Chehab 	int reg;
231cb7a01acSMauro Carvalho Chehab 
232cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
233cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_POW_MANAGE, reg);
234cb7a01acSMauro Carvalho Chehab 	/* wait 5ms before any further i2c writes are performed */
235cb7a01acSMauro Carvalho Chehab 	usleep_range(5000, 10000);
236cb7a01acSMauro Carvalho Chehab 	return 0;
237cb7a01acSMauro Carvalho Chehab }
238cb7a01acSMauro Carvalho Chehab 
adv7183_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)239cb7a01acSMauro Carvalho Chehab static int adv7183_s_routing(struct v4l2_subdev *sd,
240cb7a01acSMauro Carvalho Chehab 				u32 input, u32 output, u32 config)
241cb7a01acSMauro Carvalho Chehab {
242cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
243cb7a01acSMauro Carvalho Chehab 	int reg;
244cb7a01acSMauro Carvalho Chehab 
245cb7a01acSMauro Carvalho Chehab 	if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
246cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
247cb7a01acSMauro Carvalho Chehab 
248cb7a01acSMauro Carvalho Chehab 	if (input != decoder->input) {
249cb7a01acSMauro Carvalho Chehab 		decoder->input = input;
250cb7a01acSMauro Carvalho Chehab 		reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
251cb7a01acSMauro Carvalho Chehab 		switch (input) {
252cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE1:
253cb7a01acSMauro Carvalho Chehab 			reg |= 0x1;
254cb7a01acSMauro Carvalho Chehab 			break;
255cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE2:
256cb7a01acSMauro Carvalho Chehab 			reg |= 0x2;
257cb7a01acSMauro Carvalho Chehab 			break;
258cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE3:
259cb7a01acSMauro Carvalho Chehab 			reg |= 0x3;
260cb7a01acSMauro Carvalho Chehab 			break;
261cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE4:
262cb7a01acSMauro Carvalho Chehab 			reg |= 0x4;
263cb7a01acSMauro Carvalho Chehab 			break;
264cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE5:
265cb7a01acSMauro Carvalho Chehab 			reg |= 0x5;
266cb7a01acSMauro Carvalho Chehab 			break;
267cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE6:
268cb7a01acSMauro Carvalho Chehab 			reg |= 0xB;
269cb7a01acSMauro Carvalho Chehab 			break;
270cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE7:
271cb7a01acSMauro Carvalho Chehab 			reg |= 0xC;
272cb7a01acSMauro Carvalho Chehab 			break;
273cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE8:
274cb7a01acSMauro Carvalho Chehab 			reg |= 0xD;
275cb7a01acSMauro Carvalho Chehab 			break;
276cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE9:
277cb7a01acSMauro Carvalho Chehab 			reg |= 0xE;
278cb7a01acSMauro Carvalho Chehab 			break;
279cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPOSITE10:
280cb7a01acSMauro Carvalho Chehab 			reg |= 0xF;
281cb7a01acSMauro Carvalho Chehab 			break;
282cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO0:
283cb7a01acSMauro Carvalho Chehab 			reg |= 0x6;
284cb7a01acSMauro Carvalho Chehab 			break;
285cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO1:
286cb7a01acSMauro Carvalho Chehab 			reg |= 0x7;
287cb7a01acSMauro Carvalho Chehab 			break;
288cb7a01acSMauro Carvalho Chehab 		case ADV7183_SVIDEO2:
289cb7a01acSMauro Carvalho Chehab 			reg |= 0x8;
290cb7a01acSMauro Carvalho Chehab 			break;
291cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPONENT0:
292cb7a01acSMauro Carvalho Chehab 			reg |= 0x9;
293cb7a01acSMauro Carvalho Chehab 			break;
294cb7a01acSMauro Carvalho Chehab 		case ADV7183_COMPONENT1:
295cb7a01acSMauro Carvalho Chehab 			reg |= 0xA;
296cb7a01acSMauro Carvalho Chehab 			break;
297cb7a01acSMauro Carvalho Chehab 		default:
298cb7a01acSMauro Carvalho Chehab 			break;
299cb7a01acSMauro Carvalho Chehab 		}
300cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_IN_CTRL, reg);
301cb7a01acSMauro Carvalho Chehab 	}
302cb7a01acSMauro Carvalho Chehab 
303cb7a01acSMauro Carvalho Chehab 	if (output != decoder->output) {
304cb7a01acSMauro Carvalho Chehab 		decoder->output = output;
305cb7a01acSMauro Carvalho Chehab 		reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
306cb7a01acSMauro Carvalho Chehab 		switch (output) {
307cb7a01acSMauro Carvalho Chehab 		case ADV7183_16BIT_OUT:
308cb7a01acSMauro Carvalho Chehab 			reg |= 0x9;
309cb7a01acSMauro Carvalho Chehab 			break;
310cb7a01acSMauro Carvalho Chehab 		default:
311cb7a01acSMauro Carvalho Chehab 			reg |= 0xC;
312cb7a01acSMauro Carvalho Chehab 			break;
313cb7a01acSMauro Carvalho Chehab 		}
314cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_OUT_CTRL, reg);
315cb7a01acSMauro Carvalho Chehab 	}
316cb7a01acSMauro Carvalho Chehab 
317cb7a01acSMauro Carvalho Chehab 	return 0;
318cb7a01acSMauro Carvalho Chehab }
319cb7a01acSMauro Carvalho Chehab 
adv7183_s_ctrl(struct v4l2_ctrl * ctrl)320cb7a01acSMauro Carvalho Chehab static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
321cb7a01acSMauro Carvalho Chehab {
322cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
323cb7a01acSMauro Carvalho Chehab 	int val = ctrl->val;
324cb7a01acSMauro Carvalho Chehab 
325cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
326cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
327cb7a01acSMauro Carvalho Chehab 		if (val < 0)
328cb7a01acSMauro Carvalho Chehab 			val = 127 - val;
329cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_BRIGHTNESS, val);
330cb7a01acSMauro Carvalho Chehab 		break;
331cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
332cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_CONTRAST, val);
333cb7a01acSMauro Carvalho Chehab 		break;
334cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
335cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
336cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
337cb7a01acSMauro Carvalho Chehab 		break;
338cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
339cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
340cb7a01acSMauro Carvalho Chehab 		adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
341cb7a01acSMauro Carvalho Chehab 		break;
342cb7a01acSMauro Carvalho Chehab 	default:
343cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
344cb7a01acSMauro Carvalho Chehab 	}
345cb7a01acSMauro Carvalho Chehab 
346cb7a01acSMauro Carvalho Chehab 	return 0;
347cb7a01acSMauro Carvalho Chehab }
348cb7a01acSMauro Carvalho Chehab 
adv7183_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)349cb7a01acSMauro Carvalho Chehab static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
350cb7a01acSMauro Carvalho Chehab {
351cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
352cb7a01acSMauro Carvalho Chehab 	int reg;
353cb7a01acSMauro Carvalho Chehab 
354cb7a01acSMauro Carvalho Chehab 	/* enable autodetection block */
355cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
356cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, ADV7183_IN_CTRL, reg);
357cb7a01acSMauro Carvalho Chehab 
358cb7a01acSMauro Carvalho Chehab 	/* wait autodetection switch */
359cb7a01acSMauro Carvalho Chehab 	mdelay(10);
360cb7a01acSMauro Carvalho Chehab 
361cb7a01acSMauro Carvalho Chehab 	/* get autodetection result */
362cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_STATUS_1);
363cb7a01acSMauro Carvalho Chehab 	switch ((reg >> 0x4) & 0x7) {
364cb7a01acSMauro Carvalho Chehab 	case 0:
3657dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC;
366cb7a01acSMauro Carvalho Chehab 		break;
367cb7a01acSMauro Carvalho Chehab 	case 1:
3687dd8fbbeSHans Verkuil 		*std &= V4L2_STD_NTSC_443;
369cb7a01acSMauro Carvalho Chehab 		break;
370cb7a01acSMauro Carvalho Chehab 	case 2:
3717dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_M;
372cb7a01acSMauro Carvalho Chehab 		break;
373cb7a01acSMauro Carvalho Chehab 	case 3:
3747dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_60;
375cb7a01acSMauro Carvalho Chehab 		break;
376cb7a01acSMauro Carvalho Chehab 	case 4:
3777dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL;
378cb7a01acSMauro Carvalho Chehab 		break;
379cb7a01acSMauro Carvalho Chehab 	case 5:
3807dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
381cb7a01acSMauro Carvalho Chehab 		break;
382cb7a01acSMauro Carvalho Chehab 	case 6:
3837dd8fbbeSHans Verkuil 		*std &= V4L2_STD_PAL_Nc;
384cb7a01acSMauro Carvalho Chehab 		break;
385cb7a01acSMauro Carvalho Chehab 	case 7:
3867dd8fbbeSHans Verkuil 		*std &= V4L2_STD_SECAM;
387cb7a01acSMauro Carvalho Chehab 		break;
388cb7a01acSMauro Carvalho Chehab 	default:
389cb7a01acSMauro Carvalho Chehab 		*std = V4L2_STD_UNKNOWN;
390cb7a01acSMauro Carvalho Chehab 		break;
391cb7a01acSMauro Carvalho Chehab 	}
392cb7a01acSMauro Carvalho Chehab 
393cb7a01acSMauro Carvalho Chehab 	/* after std detection, write back user set std */
394cb7a01acSMauro Carvalho Chehab 	adv7183_s_std(sd, decoder->std);
395cb7a01acSMauro Carvalho Chehab 	return 0;
396cb7a01acSMauro Carvalho Chehab }
397cb7a01acSMauro Carvalho Chehab 
adv7183_g_input_status(struct v4l2_subdev * sd,u32 * status)398cb7a01acSMauro Carvalho Chehab static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
399cb7a01acSMauro Carvalho Chehab {
400cb7a01acSMauro Carvalho Chehab 	int reg;
401cb7a01acSMauro Carvalho Chehab 
402cb7a01acSMauro Carvalho Chehab 	*status = V4L2_IN_ST_NO_SIGNAL;
403cb7a01acSMauro Carvalho Chehab 	reg = adv7183_read(sd, ADV7183_STATUS_1);
404cb7a01acSMauro Carvalho Chehab 	if (reg < 0)
405cb7a01acSMauro Carvalho Chehab 		return reg;
406cb7a01acSMauro Carvalho Chehab 	if (reg & 0x1)
407cb7a01acSMauro Carvalho Chehab 		*status = 0;
408cb7a01acSMauro Carvalho Chehab 	return 0;
409cb7a01acSMauro Carvalho Chehab }
410cb7a01acSMauro Carvalho Chehab 
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)
414cb7a01acSMauro Carvalho Chehab {
415ebcff5fcSHans Verkuil 	if (code->pad || code->index > 0)
416cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
417cb7a01acSMauro Carvalho Chehab 
418ebcff5fcSHans Verkuil 	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
419cb7a01acSMauro Carvalho Chehab 	return 0;
420cb7a01acSMauro Carvalho Chehab }
421cb7a01acSMauro Carvalho Chehab 
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)
425cb7a01acSMauro Carvalho Chehab {
426cb7a01acSMauro Carvalho Chehab 	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;
431cb7a01acSMauro Carvalho Chehab 
432f5fe58fdSBoris BREZILLON 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
433cb7a01acSMauro Carvalho Chehab 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
434cb7a01acSMauro Carvalho Chehab 	if (decoder->std & V4L2_STD_525_60) {
435cb7a01acSMauro Carvalho Chehab 		fmt->field = V4L2_FIELD_SEQ_TB;
436cb7a01acSMauro Carvalho Chehab 		fmt->width = 720;
437cb7a01acSMauro Carvalho Chehab 		fmt->height = 480;
438cb7a01acSMauro Carvalho Chehab 	} else {
439cb7a01acSMauro Carvalho Chehab 		fmt->field = V4L2_FIELD_SEQ_BT;
440cb7a01acSMauro Carvalho Chehab 		fmt->width = 720;
441cb7a01acSMauro Carvalho Chehab 		fmt->height = 576;
442cb7a01acSMauro Carvalho Chehab 	}
443717fd5b4SHans Verkuil 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
444cb7a01acSMauro Carvalho Chehab 		decoder->fmt = *fmt;
445717fd5b4SHans Verkuil 	else
4460d346d2aSTomi Valkeinen 		sd_state->pads->try_fmt = *fmt;
447cb7a01acSMauro Carvalho Chehab 	return 0;
448cb7a01acSMauro Carvalho Chehab }
449cb7a01acSMauro Carvalho Chehab 
adv7183_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)450da298c6dSHans Verkuil static int adv7183_get_fmt(struct v4l2_subdev *sd,
4510d346d2aSTomi Valkeinen 		struct v4l2_subdev_state *sd_state,
452da298c6dSHans Verkuil 		struct v4l2_subdev_format *format)
453cb7a01acSMauro Carvalho Chehab {
454cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
455cb7a01acSMauro Carvalho Chehab 
456da298c6dSHans Verkuil 	if (format->pad)
457da298c6dSHans Verkuil 		return -EINVAL;
458da298c6dSHans Verkuil 
459da298c6dSHans Verkuil 	format->format = decoder->fmt;
460cb7a01acSMauro Carvalho Chehab 	return 0;
461cb7a01acSMauro Carvalho Chehab }
462cb7a01acSMauro Carvalho Chehab 
adv7183_s_stream(struct v4l2_subdev * sd,int enable)463cb7a01acSMauro Carvalho Chehab static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
464cb7a01acSMauro Carvalho Chehab {
465cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder = to_adv7183(sd);
466cb7a01acSMauro Carvalho Chehab 
467cb7a01acSMauro Carvalho Chehab 	if (enable)
4683e4fcec0SLinus Walleij 		gpiod_set_value(decoder->oe_pin, 1);
469cb7a01acSMauro Carvalho Chehab 	else
4703e4fcec0SLinus Walleij 		gpiod_set_value(decoder->oe_pin, 0);
471cb7a01acSMauro Carvalho Chehab 	udelay(1);
472cb7a01acSMauro Carvalho Chehab 	return 0;
473cb7a01acSMauro Carvalho Chehab }
474cb7a01acSMauro Carvalho Chehab 
475cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
adv7183_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)476cb7a01acSMauro Carvalho Chehab static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
477cb7a01acSMauro Carvalho Chehab {
478cb7a01acSMauro Carvalho Chehab 	reg->val = adv7183_read(sd, reg->reg & 0xff);
479cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
480cb7a01acSMauro Carvalho Chehab 	return 0;
481cb7a01acSMauro Carvalho Chehab }
482cb7a01acSMauro Carvalho Chehab 
adv7183_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)483977ba3b1SHans Verkuil static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
484cb7a01acSMauro Carvalho Chehab {
485cb7a01acSMauro Carvalho Chehab 	adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
486cb7a01acSMauro Carvalho Chehab 	return 0;
487cb7a01acSMauro Carvalho Chehab }
488cb7a01acSMauro Carvalho Chehab #endif
489cb7a01acSMauro Carvalho Chehab 
490cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
491cb7a01acSMauro Carvalho Chehab 	.s_ctrl = adv7183_s_ctrl,
492cb7a01acSMauro Carvalho Chehab };
493cb7a01acSMauro Carvalho Chehab 
494cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7183_core_ops = {
495cb7a01acSMauro Carvalho Chehab 	.log_status = adv7183_log_status,
496cb7a01acSMauro Carvalho Chehab 	.reset = adv7183_reset,
497cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
498cb7a01acSMauro Carvalho Chehab 	.g_register = adv7183_g_register,
499cb7a01acSMauro Carvalho Chehab 	.s_register = adv7183_s_register,
500cb7a01acSMauro Carvalho Chehab #endif
501cb7a01acSMauro Carvalho Chehab };
502cb7a01acSMauro Carvalho Chehab 
503cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7183_video_ops = {
5048774bed9SLaurent Pinchart 	.g_std = adv7183_g_std,
5058774bed9SLaurent Pinchart 	.s_std = adv7183_s_std,
506cb7a01acSMauro Carvalho Chehab 	.s_routing = adv7183_s_routing,
507cb7a01acSMauro Carvalho Chehab 	.querystd = adv7183_querystd,
508cb7a01acSMauro Carvalho Chehab 	.g_input_status = adv7183_g_input_status,
509cb7a01acSMauro Carvalho Chehab 	.s_stream = adv7183_s_stream,
510cb7a01acSMauro Carvalho Chehab };
511cb7a01acSMauro Carvalho Chehab 
512ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops adv7183_pad_ops = {
513ebcff5fcSHans Verkuil 	.enum_mbus_code = adv7183_enum_mbus_code,
514da298c6dSHans Verkuil 	.get_fmt = adv7183_get_fmt,
515717fd5b4SHans Verkuil 	.set_fmt = adv7183_set_fmt,
516ebcff5fcSHans Verkuil };
517ebcff5fcSHans Verkuil 
518cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7183_ops = {
519cb7a01acSMauro Carvalho Chehab 	.core = &adv7183_core_ops,
520cb7a01acSMauro Carvalho Chehab 	.video = &adv7183_video_ops,
521ebcff5fcSHans Verkuil 	.pad = &adv7183_pad_ops,
522cb7a01acSMauro Carvalho Chehab };
523cb7a01acSMauro Carvalho Chehab 
adv7183_probe(struct i2c_client * client)524f31dab40SUwe Kleine-König static int adv7183_probe(struct i2c_client *client)
525cb7a01acSMauro Carvalho Chehab {
526cb7a01acSMauro Carvalho Chehab 	struct adv7183 *decoder;
527cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
528cb7a01acSMauro Carvalho Chehab 	struct v4l2_ctrl_handler *hdl;
529cb7a01acSMauro Carvalho Chehab 	int ret;
530717fd5b4SHans Verkuil 	struct v4l2_subdev_format fmt = {
531717fd5b4SHans Verkuil 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
532717fd5b4SHans Verkuil 	};
533cb7a01acSMauro Carvalho Chehab 
534cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
535cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
536cb7a01acSMauro Carvalho Chehab 		return -EIO;
537cb7a01acSMauro Carvalho Chehab 
538cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
539cb7a01acSMauro Carvalho Chehab 			client->addr << 1, client->adapter->name);
540cb7a01acSMauro Carvalho Chehab 
541c02b211dSLaurent Pinchart 	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
542cb7a01acSMauro Carvalho Chehab 	if (decoder == NULL)
543cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
544cb7a01acSMauro Carvalho Chehab 
5453e4fcec0SLinus Walleij 	/*
5463e4fcec0SLinus Walleij 	 * Requesting high will assert reset, the line should be
5473e4fcec0SLinus Walleij 	 * flagged as active low in descriptor table or machine description.
5483e4fcec0SLinus Walleij 	 */
5493e4fcec0SLinus Walleij 	decoder->reset_pin = devm_gpiod_get(&client->dev, "reset",
5503e4fcec0SLinus Walleij 					    GPIOD_OUT_HIGH);
5513e4fcec0SLinus Walleij 	if (IS_ERR(decoder->reset_pin))
5523e4fcec0SLinus Walleij 		return PTR_ERR(decoder->reset_pin);
5533e4fcec0SLinus Walleij 	gpiod_set_consumer_name(decoder->reset_pin, "ADV7183 Reset");
5543e4fcec0SLinus Walleij 	/*
5553e4fcec0SLinus Walleij 	 * Requesting low will start with output disabled, the line should be
5563e4fcec0SLinus Walleij 	 * flagged as active low in descriptor table or machine description.
5573e4fcec0SLinus Walleij 	 */
5583e4fcec0SLinus Walleij 	decoder->oe_pin = devm_gpiod_get(&client->dev, "oe",
5593e4fcec0SLinus Walleij 					 GPIOD_OUT_LOW);
5603e4fcec0SLinus Walleij 	if (IS_ERR(decoder->oe_pin))
5613e4fcec0SLinus Walleij 		return PTR_ERR(decoder->oe_pin);
5623e4fcec0SLinus Walleij 	gpiod_set_consumer_name(decoder->reset_pin, "ADV7183 Output Enable");
563cb7a01acSMauro Carvalho Chehab 
564cb7a01acSMauro Carvalho Chehab 	sd = &decoder->sd;
565cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
566cb7a01acSMauro Carvalho Chehab 
567cb7a01acSMauro Carvalho Chehab 	hdl = &decoder->hdl;
568cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(hdl, 4);
569cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
570cb7a01acSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
571cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
572cb7a01acSMauro Carvalho Chehab 			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
573cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
574cb7a01acSMauro Carvalho Chehab 			V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
575cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
576cb7a01acSMauro Carvalho Chehab 			V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
577cb7a01acSMauro Carvalho Chehab 	/* hook the control handler into the driver */
578cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = hdl;
579cb7a01acSMauro Carvalho Chehab 	if (hdl->error) {
580cb7a01acSMauro Carvalho Chehab 		ret = hdl->error;
581cb7a01acSMauro Carvalho Chehab 
582cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(hdl);
583b015ba29SLaurent Pinchart 		return ret;
584cb7a01acSMauro Carvalho Chehab 	}
585cb7a01acSMauro Carvalho Chehab 
586cb7a01acSMauro Carvalho Chehab 	/* v4l2 doesn't support an autodetect standard, pick PAL as default */
587cb7a01acSMauro Carvalho Chehab 	decoder->std = V4L2_STD_PAL;
588cb7a01acSMauro Carvalho Chehab 	decoder->input = ADV7183_COMPOSITE4;
589cb7a01acSMauro Carvalho Chehab 	decoder->output = ADV7183_8BIT_OUT;
590cb7a01acSMauro Carvalho Chehab 
591cb7a01acSMauro Carvalho Chehab 	/* reset chip */
592cb7a01acSMauro Carvalho Chehab 	/* reset pulse width at least 5ms */
593cb7a01acSMauro Carvalho Chehab 	mdelay(10);
5943e4fcec0SLinus Walleij 	/* De-assert reset line (descriptor tagged active low) */
5953e4fcec0SLinus Walleij 	gpiod_set_value(decoder->reset_pin, 0);
596cb7a01acSMauro Carvalho Chehab 	/* wait 5ms before any further i2c writes are performed */
597cb7a01acSMauro Carvalho Chehab 	mdelay(5);
598cb7a01acSMauro Carvalho Chehab 
599cb7a01acSMauro Carvalho Chehab 	adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
600cb7a01acSMauro Carvalho Chehab 	adv7183_s_std(sd, decoder->std);
601717fd5b4SHans Verkuil 	fmt.format.width = 720;
602717fd5b4SHans Verkuil 	fmt.format.height = 576;
603717fd5b4SHans Verkuil 	adv7183_set_fmt(sd, NULL, &fmt);
604cb7a01acSMauro Carvalho Chehab 
605cb7a01acSMauro Carvalho Chehab 	/* initialize the hardware to the default control values */
606cb7a01acSMauro Carvalho Chehab 	ret = v4l2_ctrl_handler_setup(hdl);
607cb7a01acSMauro Carvalho Chehab 	if (ret) {
608cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(hdl);
609b015ba29SLaurent Pinchart 		return ret;
610cb7a01acSMauro Carvalho Chehab 	}
611cb7a01acSMauro Carvalho Chehab 
612cb7a01acSMauro Carvalho Chehab 	return 0;
613cb7a01acSMauro Carvalho Chehab }
614cb7a01acSMauro Carvalho Chehab 
adv7183_remove(struct i2c_client * client)615ed5c2f5fSUwe Kleine-König static void adv7183_remove(struct i2c_client *client)
616cb7a01acSMauro Carvalho Chehab {
617cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
618cb7a01acSMauro Carvalho Chehab 
619cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
620cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(sd->ctrl_handler);
621cb7a01acSMauro Carvalho Chehab }
622cb7a01acSMauro Carvalho Chehab 
623cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7183_id[] = {
624cb7a01acSMauro Carvalho Chehab 	{"adv7183", 0},
625cb7a01acSMauro Carvalho Chehab 	{},
626cb7a01acSMauro Carvalho Chehab };
627cb7a01acSMauro Carvalho Chehab 
628cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, adv7183_id);
629cb7a01acSMauro Carvalho Chehab 
630cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7183_driver = {
631cb7a01acSMauro Carvalho Chehab 	.driver = {
632cb7a01acSMauro Carvalho Chehab 		.name   = "adv7183",
633cb7a01acSMauro Carvalho Chehab 	},
634*aaeb31c0SUwe Kleine-König 	.probe          = adv7183_probe,
6354c62e976SGreg Kroah-Hartman 	.remove         = adv7183_remove,
636cb7a01acSMauro Carvalho Chehab 	.id_table       = adv7183_id,
637cb7a01acSMauro Carvalho Chehab };
638cb7a01acSMauro Carvalho Chehab 
63901aea0bfSWei Yongjun module_i2c_driver(adv7183_driver);
640cb7a01acSMauro Carvalho Chehab 
641cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
642cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
643cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
644