xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/ths8200.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * ths8200 - Texas Instruments THS8200 video encoder driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you may redistribute it and/or modify
7*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun  * the Free Software Foundation; version 2 of the License.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
11*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License as
12*4882a593Smuzhiyun  * published by the Free Software Foundation version 2.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * This program is distributed .as is. WITHOUT ANY WARRANTY of any
15*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
16*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*4882a593Smuzhiyun  * GNU General Public License for more details.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/i2c.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/of.h>
23*4882a593Smuzhiyun #include <linux/v4l2-dv-timings.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <media/v4l2-dv-timings.h>
26*4882a593Smuzhiyun #include <media/v4l2-async.h>
27*4882a593Smuzhiyun #include <media/v4l2-device.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "ths8200_regs.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static int debug;
32*4882a593Smuzhiyun module_param(debug, int, 0644);
33*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "debug level (0-2)");
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun MODULE_DESCRIPTION("Texas Instruments THS8200 video encoder driver");
36*4882a593Smuzhiyun MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
37*4882a593Smuzhiyun MODULE_AUTHOR("Martin Bugge <martin.bugge@cisco.com>");
38*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun struct ths8200_state {
41*4882a593Smuzhiyun 	struct v4l2_subdev sd;
42*4882a593Smuzhiyun 	uint8_t chip_version;
43*4882a593Smuzhiyun 	/* Is the ths8200 powered on? */
44*4882a593Smuzhiyun 	bool power_on;
45*4882a593Smuzhiyun 	struct v4l2_dv_timings dv_timings;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
49*4882a593Smuzhiyun 	.type = V4L2_DV_BT_656_1120,
50*4882a593Smuzhiyun 	/* keep this initialization for compatibility with GCC < 4.4.6 */
51*4882a593Smuzhiyun 	.reserved = { 0 },
52*4882a593Smuzhiyun 	V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1080, 25000000, 148500000,
53*4882a593Smuzhiyun 		V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
to_state(struct v4l2_subdev * sd)56*4882a593Smuzhiyun static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	return container_of(sd, struct ths8200_state, sd);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
htotal(const struct v4l2_bt_timings * t)61*4882a593Smuzhiyun static inline unsigned htotal(const struct v4l2_bt_timings *t)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	return V4L2_DV_BT_FRAME_WIDTH(t);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
vtotal(const struct v4l2_bt_timings * t)66*4882a593Smuzhiyun static inline unsigned vtotal(const struct v4l2_bt_timings *t)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	return V4L2_DV_BT_FRAME_HEIGHT(t);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
ths8200_read(struct v4l2_subdev * sd,u8 reg)71*4882a593Smuzhiyun static int ths8200_read(struct v4l2_subdev *sd, u8 reg)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return i2c_smbus_read_byte_data(client, reg);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
ths8200_write(struct v4l2_subdev * sd,u8 reg,u8 val)78*4882a593Smuzhiyun static int ths8200_write(struct v4l2_subdev *sd, u8 reg, u8 val)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
81*4882a593Smuzhiyun 	int ret;
82*4882a593Smuzhiyun 	int i;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
85*4882a593Smuzhiyun 		ret = i2c_smbus_write_byte_data(client, reg, val);
86*4882a593Smuzhiyun 		if (ret == 0)
87*4882a593Smuzhiyun 			return 0;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 	v4l2_err(sd, "I2C Write Problem\n");
90*4882a593Smuzhiyun 	return ret;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* To set specific bits in the register, a clear-mask is given (to be AND-ed),
94*4882a593Smuzhiyun  * and then the value-mask (to be OR-ed).
95*4882a593Smuzhiyun  */
96*4882a593Smuzhiyun static inline void
ths8200_write_and_or(struct v4l2_subdev * sd,u8 reg,uint8_t clr_mask,uint8_t val_mask)97*4882a593Smuzhiyun ths8200_write_and_or(struct v4l2_subdev *sd, u8 reg,
98*4882a593Smuzhiyun 		     uint8_t clr_mask, uint8_t val_mask)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	ths8200_write(sd, reg, (ths8200_read(sd, reg) & clr_mask) | val_mask);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
104*4882a593Smuzhiyun 
ths8200_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)105*4882a593Smuzhiyun static int ths8200_g_register(struct v4l2_subdev *sd,
106*4882a593Smuzhiyun 			      struct v4l2_dbg_register *reg)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	reg->val = ths8200_read(sd, reg->reg & 0xff);
109*4882a593Smuzhiyun 	reg->size = 1;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
ths8200_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)114*4882a593Smuzhiyun static int ths8200_s_register(struct v4l2_subdev *sd,
115*4882a593Smuzhiyun 			      const struct v4l2_dbg_register *reg)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	ths8200_write(sd, reg->reg & 0xff, reg->val & 0xff);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun 
ths8200_log_status(struct v4l2_subdev * sd)123*4882a593Smuzhiyun static int ths8200_log_status(struct v4l2_subdev *sd)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct ths8200_state *state = to_state(sd);
126*4882a593Smuzhiyun 	uint8_t reg_03 = ths8200_read(sd, THS8200_CHIP_CTL);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	v4l2_info(sd, "----- Chip status -----\n");
129*4882a593Smuzhiyun 	v4l2_info(sd, "version: %u\n", state->chip_version);
130*4882a593Smuzhiyun 	v4l2_info(sd, "power: %s\n", (reg_03 & 0x0c) ? "off" : "on");
131*4882a593Smuzhiyun 	v4l2_info(sd, "reset: %s\n", (reg_03 & 0x01) ? "off" : "on");
132*4882a593Smuzhiyun 	v4l2_info(sd, "test pattern: %s\n",
133*4882a593Smuzhiyun 		  (reg_03 & 0x20) ? "enabled" : "disabled");
134*4882a593Smuzhiyun 	v4l2_info(sd, "format: %ux%u\n",
135*4882a593Smuzhiyun 		  ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_MSB) * 256 +
136*4882a593Smuzhiyun 		  ths8200_read(sd, THS8200_DTG2_PIXEL_CNT_LSB),
137*4882a593Smuzhiyun 		  (ths8200_read(sd, THS8200_DTG2_LINE_CNT_MSB) & 0x07) * 256 +
138*4882a593Smuzhiyun 		  ths8200_read(sd, THS8200_DTG2_LINE_CNT_LSB));
139*4882a593Smuzhiyun 	v4l2_print_dv_timings(sd->name, "Configured format:",
140*4882a593Smuzhiyun 			      &state->dv_timings, true);
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /* Power up/down ths8200 */
ths8200_s_power(struct v4l2_subdev * sd,int on)145*4882a593Smuzhiyun static int ths8200_s_power(struct v4l2_subdev *sd, int on)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct ths8200_state *state = to_state(sd);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	state->power_on = on;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* Power up/down - leave in reset state until input video is present */
154*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xf2, (on ? 0x00 : 0x0c));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops ths8200_core_ops = {
160*4882a593Smuzhiyun 	.log_status = ths8200_log_status,
161*4882a593Smuzhiyun 	.s_power = ths8200_s_power,
162*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
163*4882a593Smuzhiyun 	.g_register = ths8200_g_register,
164*4882a593Smuzhiyun 	.s_register = ths8200_s_register,
165*4882a593Smuzhiyun #endif
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
169*4882a593Smuzhiyun  * V4L2 subdev video operations
170*4882a593Smuzhiyun  */
171*4882a593Smuzhiyun 
ths8200_s_stream(struct v4l2_subdev * sd,int enable)172*4882a593Smuzhiyun static int ths8200_s_stream(struct v4l2_subdev *sd, int enable)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct ths8200_state *state = to_state(sd);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (enable && !state->power_on)
177*4882a593Smuzhiyun 		ths8200_s_power(sd, true);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0xfe,
180*4882a593Smuzhiyun 			     (enable ? 0x01 : 0x00));
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: %sable\n",
183*4882a593Smuzhiyun 		 __func__, (enable ? "en" : "dis"));
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
ths8200_core_init(struct v4l2_subdev * sd)188*4882a593Smuzhiyun static void ths8200_core_init(struct v4l2_subdev *sd)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	/* setup clocks */
191*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_CHIP_CTL, 0x3f, 0xc0);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/**** Data path control (DATA) ****/
194*4882a593Smuzhiyun 	/* Set FSADJ 700 mV,
195*4882a593Smuzhiyun 	 * bypass 422-444 interpolation,
196*4882a593Smuzhiyun 	 * input format 30 bit RGB444
197*4882a593Smuzhiyun 	 */
198*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DATA_CNTL, 0x70);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	/* DTG Mode (Video blocked during blanking
201*4882a593Smuzhiyun 	 * VESA slave
202*4882a593Smuzhiyun 	 */
203*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_MODE, 0x87);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/**** Display Timing Generator Control, Part 1 (DTG1). ****/
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/* Disable embedded syncs on the output by setting
208*4882a593Smuzhiyun 	 * the amplitude to zero for all channels.
209*4882a593Smuzhiyun 	 */
210*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_Y_SYNC_MSB, 0x00);
211*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_CBCR_SYNC_MSB, 0x00);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
ths8200_setup(struct v4l2_subdev * sd,struct v4l2_bt_timings * bt)214*4882a593Smuzhiyun static void ths8200_setup(struct v4l2_subdev *sd, struct v4l2_bt_timings *bt)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	uint8_t polarity = 0;
217*4882a593Smuzhiyun 	uint16_t line_start_active_video = (bt->vsync + bt->vbackporch);
218*4882a593Smuzhiyun 	uint16_t line_start_front_porch  = (vtotal(bt) - bt->vfrontporch);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/*** System ****/
221*4882a593Smuzhiyun 	/* Set chip in reset while it is configured */
222*4882a593Smuzhiyun 	ths8200_s_stream(sd, false);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	/* configure video output timings */
225*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_A, bt->hsync);
226*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_B, bt->hfrontporch);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/* Zero for progressive scan formats.*/
229*4882a593Smuzhiyun 	if (!bt->interlaced)
230*4882a593Smuzhiyun 		ths8200_write(sd, THS8200_DTG1_SPEC_C, 0x00);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* Distance from leading edge of h sync to start of active video.
233*4882a593Smuzhiyun 	 * MSB in 0x2b
234*4882a593Smuzhiyun 	 */
235*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_D_LSB,
236*4882a593Smuzhiyun 		      (bt->hbackporch + bt->hsync) & 0xff);
237*4882a593Smuzhiyun 	/* Zero for SDTV-mode. MSB in 0x2b */
238*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_E_LSB, 0x00);
239*4882a593Smuzhiyun 	/*
240*4882a593Smuzhiyun 	 * MSB for dtg1_spec(d/e/h). See comment for
241*4882a593Smuzhiyun 	 * corresponding LSB registers.
242*4882a593Smuzhiyun 	 */
243*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_DEH_MSB,
244*4882a593Smuzhiyun 		      ((bt->hbackporch + bt->hsync) & 0x100) >> 1);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* h front porch */
247*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_K_LSB, (bt->hfrontporch) & 0xff);
248*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_K_MSB,
249*4882a593Smuzhiyun 		      ((bt->hfrontporch) & 0x700) >> 8);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* Half the line length. Used to calculate SDTV line types. */
252*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_G_LSB, (htotal(bt)/2) & 0xff);
253*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_SPEC_G_MSB,
254*4882a593Smuzhiyun 		      ((htotal(bt)/2) >> 8) & 0x0f);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* Total pixels per line (ex. 720p: 1650) */
257*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_MSB, htotal(bt) >> 8);
258*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_TOT_PIXELS_LSB, htotal(bt) & 0xff);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* Frame height and field height */
261*4882a593Smuzhiyun 	/* Field height should be programmed higher than frame_size for
262*4882a593Smuzhiyun 	 * progressive scan formats
263*4882a593Smuzhiyun 	 */
264*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_FRAME_FIELD_SZ_MSB,
265*4882a593Smuzhiyun 		      ((vtotal(bt) >> 4) & 0xf0) + 0x7);
266*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG1_FRAME_SZ_LSB, vtotal(bt) & 0xff);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* Should be programmed higher than frame_size
269*4882a593Smuzhiyun 	 * for progressive formats
270*4882a593Smuzhiyun 	 */
271*4882a593Smuzhiyun 	if (!bt->interlaced)
272*4882a593Smuzhiyun 		ths8200_write(sd, THS8200_DTG1_FIELD_SZ_LSB, 0xff);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	/**** Display Timing Generator Control, Part 2 (DTG2). ****/
275*4882a593Smuzhiyun 	/* Set breakpoint line numbers and types
276*4882a593Smuzhiyun 	 * THS8200 generates line types with different properties. A line type
277*4882a593Smuzhiyun 	 * that sets all the RGB-outputs to zero is used in the blanking areas,
278*4882a593Smuzhiyun 	 * while a line type that enable the RGB-outputs is used in active video
279*4882a593Smuzhiyun 	 * area. The line numbers for start of active video, start of front
280*4882a593Smuzhiyun 	 * porch and after the last line in the frame must be set with the
281*4882a593Smuzhiyun 	 * corresponding line types.
282*4882a593Smuzhiyun 	 *
283*4882a593Smuzhiyun 	 * Line types:
284*4882a593Smuzhiyun 	 * 0x9 - Full normal sync pulse: Blocks data when dtg1_pass is off.
285*4882a593Smuzhiyun 	 *       Used in blanking area.
286*4882a593Smuzhiyun 	 * 0x0 - Active video: Video data is always passed. Used in active
287*4882a593Smuzhiyun 	 *       video area.
288*4882a593Smuzhiyun 	 */
289*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_DTG2_BP1_2_MSB, 0x88,
290*4882a593Smuzhiyun 			     ((line_start_active_video >> 4) & 0x70) +
291*4882a593Smuzhiyun 			     ((line_start_front_porch >> 8) & 0x07));
292*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_BP3_4_MSB, ((vtotal(bt)) >> 4) & 0x70);
293*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_BP1_LSB, line_start_active_video & 0xff);
294*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_BP2_LSB, line_start_front_porch & 0xff);
295*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_BP3_LSB, (vtotal(bt)) & 0xff);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* line types */
298*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_LINETYPE1, 0x90);
299*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_LINETYPE2, 0x90);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/* h sync width transmitted */
302*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_HLENGTH_LSB, bt->hsync & 0xff);
303*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0x3f,
304*4882a593Smuzhiyun 			     (bt->hsync >> 2) & 0xc0);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* The pixel value h sync is asserted on */
307*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_DTG2_HLENGTH_LSB_HDLY_MSB, 0xe0,
308*4882a593Smuzhiyun 			     (htotal(bt) >> 8) & 0x1f);
309*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_HLENGTH_HDLY_LSB, htotal(bt));
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	/* v sync width transmitted (must add 1 to get correct output) */
312*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VLENGTH1_LSB, (bt->vsync + 1) & 0xff);
313*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0x3f,
314*4882a593Smuzhiyun 			     ((bt->vsync + 1) >> 2) & 0xc0);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	/* The pixel value v sync is asserted on (must add 1 to get correct output) */
317*4882a593Smuzhiyun 	ths8200_write_and_or(sd, THS8200_DTG2_VLENGTH1_MSB_VDLY1_MSB, 0xf8,
318*4882a593Smuzhiyun 			     ((vtotal(bt) + 1) >> 8) & 0x7);
319*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VDLY1_LSB, vtotal(bt) + 1);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/* For progressive video vlength2 must be set to all 0 and vdly2 must
322*4882a593Smuzhiyun 	 * be set to all 1.
323*4882a593Smuzhiyun 	 */
324*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VLENGTH2_LSB, 0x00);
325*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VLENGTH2_MSB_VDLY2_MSB, 0x07);
326*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VDLY2_LSB, 0xff);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/* Internal delay factors to synchronize the sync pulses and the data */
329*4882a593Smuzhiyun 	/* Experimental values delays (hor 0, ver 0) */
330*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_MSB, 0);
331*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_HS_IN_DLY_LSB, 0);
332*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_MSB, 0);
333*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_VS_IN_DLY_LSB, 0);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* Polarity of received and transmitted sync signals */
336*4882a593Smuzhiyun 	if (bt->polarities & V4L2_DV_HSYNC_POS_POL) {
337*4882a593Smuzhiyun 		polarity |= 0x01; /* HS_IN */
338*4882a593Smuzhiyun 		polarity |= 0x08; /* HS_OUT */
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 	if (bt->polarities & V4L2_DV_VSYNC_POS_POL) {
341*4882a593Smuzhiyun 		polarity |= 0x02; /* VS_IN */
342*4882a593Smuzhiyun 		polarity |= 0x10; /* VS_OUT */
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	/* RGB mode, no embedded timings */
346*4882a593Smuzhiyun 	/* Timing of video input bus is derived from HS, VS, and FID dedicated
347*4882a593Smuzhiyun 	 * inputs
348*4882a593Smuzhiyun 	 */
349*4882a593Smuzhiyun 	ths8200_write(sd, THS8200_DTG2_CNTL, 0x44 | polarity);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	/* leave reset */
352*4882a593Smuzhiyun 	ths8200_s_stream(sd, true);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: frame %dx%d, polarity %d\n"
355*4882a593Smuzhiyun 		 "horizontal: front porch %d, back porch %d, sync %d\n"
356*4882a593Smuzhiyun 		 "vertical: sync %d\n", __func__, htotal(bt), vtotal(bt),
357*4882a593Smuzhiyun 		 polarity, bt->hfrontporch, bt->hbackporch,
358*4882a593Smuzhiyun 		 bt->hsync, bt->vsync);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
ths8200_s_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)361*4882a593Smuzhiyun static int ths8200_s_dv_timings(struct v4l2_subdev *sd,
362*4882a593Smuzhiyun 				struct v4l2_dv_timings *timings)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	struct ths8200_state *state = to_state(sd);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (!v4l2_valid_dv_timings(timings, &ths8200_timings_cap,
369*4882a593Smuzhiyun 				NULL, NULL))
370*4882a593Smuzhiyun 		return -EINVAL;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (!v4l2_find_dv_timings_cap(timings, &ths8200_timings_cap, 10,
373*4882a593Smuzhiyun 				NULL, NULL)) {
374*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "Unsupported format\n");
375*4882a593Smuzhiyun 		return -EINVAL;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	/* save timings */
381*4882a593Smuzhiyun 	state->dv_timings = *timings;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	ths8200_setup(sd, &timings->bt);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return 0;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
ths8200_g_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)388*4882a593Smuzhiyun static int ths8200_g_dv_timings(struct v4l2_subdev *sd,
389*4882a593Smuzhiyun 				struct v4l2_dv_timings *timings)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	struct ths8200_state *state = to_state(sd);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	*timings = state->dv_timings;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
ths8200_enum_dv_timings(struct v4l2_subdev * sd,struct v4l2_enum_dv_timings * timings)400*4882a593Smuzhiyun static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
401*4882a593Smuzhiyun 				   struct v4l2_enum_dv_timings *timings)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	if (timings->pad != 0)
404*4882a593Smuzhiyun 		return -EINVAL;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	return v4l2_enum_dv_timings_cap(timings, &ths8200_timings_cap,
407*4882a593Smuzhiyun 			NULL, NULL);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
ths8200_dv_timings_cap(struct v4l2_subdev * sd,struct v4l2_dv_timings_cap * cap)410*4882a593Smuzhiyun static int ths8200_dv_timings_cap(struct v4l2_subdev *sd,
411*4882a593Smuzhiyun 				  struct v4l2_dv_timings_cap *cap)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	if (cap->pad != 0)
414*4882a593Smuzhiyun 		return -EINVAL;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	*cap = ths8200_timings_cap;
417*4882a593Smuzhiyun 	return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun /* Specific video subsystem operation handlers */
421*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops ths8200_video_ops = {
422*4882a593Smuzhiyun 	.s_stream = ths8200_s_stream,
423*4882a593Smuzhiyun 	.s_dv_timings = ths8200_s_dv_timings,
424*4882a593Smuzhiyun 	.g_dv_timings = ths8200_g_dv_timings,
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops ths8200_pad_ops = {
428*4882a593Smuzhiyun 	.enum_dv_timings = ths8200_enum_dv_timings,
429*4882a593Smuzhiyun 	.dv_timings_cap = ths8200_dv_timings_cap,
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun /* V4L2 top level operation handlers */
433*4882a593Smuzhiyun static const struct v4l2_subdev_ops ths8200_ops = {
434*4882a593Smuzhiyun 	.core  = &ths8200_core_ops,
435*4882a593Smuzhiyun 	.video = &ths8200_video_ops,
436*4882a593Smuzhiyun 	.pad = &ths8200_pad_ops,
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun 
ths8200_probe(struct i2c_client * client)439*4882a593Smuzhiyun static int ths8200_probe(struct i2c_client *client)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	struct ths8200_state *state;
442*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
443*4882a593Smuzhiyun 	int error;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* Check if the adapter supports the needed features */
446*4882a593Smuzhiyun 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
447*4882a593Smuzhiyun 		return -EIO;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
450*4882a593Smuzhiyun 	if (!state)
451*4882a593Smuzhiyun 		return -ENOMEM;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	sd = &state->sd;
454*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &ths8200_ops);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	state->chip_version = ths8200_read(sd, THS8200_VERSION);
457*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "chip version 0x%x\n", state->chip_version);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	ths8200_core_init(sd);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	error = v4l2_async_register_subdev(&state->sd);
462*4882a593Smuzhiyun 	if (error)
463*4882a593Smuzhiyun 		return error;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
466*4882a593Smuzhiyun 		  client->addr << 1, client->adapter->name);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
ths8200_remove(struct i2c_client * client)471*4882a593Smuzhiyun static int ths8200_remove(struct i2c_client *client)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
474*4882a593Smuzhiyun 	struct ths8200_state *decoder = to_state(sd);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
477*4882a593Smuzhiyun 		 client->addr << 1, client->adapter->name);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	ths8200_s_power(sd, false);
480*4882a593Smuzhiyun 	v4l2_async_unregister_subdev(&decoder->sd);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun static const struct i2c_device_id ths8200_id[] = {
486*4882a593Smuzhiyun 	{ "ths8200", 0 },
487*4882a593Smuzhiyun 	{},
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, ths8200_id);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF)
492*4882a593Smuzhiyun static const struct of_device_id ths8200_of_match[] = {
493*4882a593Smuzhiyun 	{ .compatible = "ti,ths8200", },
494*4882a593Smuzhiyun 	{ /* sentinel */ },
495*4882a593Smuzhiyun };
496*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, ths8200_of_match);
497*4882a593Smuzhiyun #endif
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun static struct i2c_driver ths8200_driver = {
500*4882a593Smuzhiyun 	.driver = {
501*4882a593Smuzhiyun 		.name = "ths8200",
502*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(ths8200_of_match),
503*4882a593Smuzhiyun 	},
504*4882a593Smuzhiyun 	.probe_new = ths8200_probe,
505*4882a593Smuzhiyun 	.remove = ths8200_remove,
506*4882a593Smuzhiyun 	.id_table = ths8200_id,
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun module_i2c_driver(ths8200_driver);
510