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