xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/tc35874x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * tc35874x - Toshiba HDMI to CSI-2 bridge
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
5*4882a593Smuzhiyun  * reserved.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This program is free software; you may redistribute it and/or modify
8*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
9*4882a593Smuzhiyun  * the Free Software Foundation; version 2 of the License.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
15*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18*4882a593Smuzhiyun  * SOFTWARE.
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * References (c = chapter, p = page):
24*4882a593Smuzhiyun  * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60
25*4882a593Smuzhiyun  * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls
26*4882a593Smuzhiyun  * REF_02 - Toshiba, TC358749XBG (H2C+), Functional Specification, Rev 0.74
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <linux/kernel.h>
30*4882a593Smuzhiyun #include <linux/module.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun #include <linux/i2c.h>
33*4882a593Smuzhiyun #include <linux/clk.h>
34*4882a593Smuzhiyun #include <linux/delay.h>
35*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
36*4882a593Smuzhiyun #include <linux/interrupt.h>
37*4882a593Smuzhiyun #include <linux/timer.h>
38*4882a593Smuzhiyun #include <linux/of_graph.h>
39*4882a593Smuzhiyun #include <linux/videodev2.h>
40*4882a593Smuzhiyun #include <linux/workqueue.h>
41*4882a593Smuzhiyun #include <linux/v4l2-dv-timings.h>
42*4882a593Smuzhiyun #include <linux/hdmi.h>
43*4882a593Smuzhiyun #include <linux/version.h>
44*4882a593Smuzhiyun #include <linux/compat.h>
45*4882a593Smuzhiyun #include <linux/rk-camera-module.h>
46*4882a593Smuzhiyun #include <media/v4l2-dv-timings.h>
47*4882a593Smuzhiyun #include <media/v4l2-device.h>
48*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
49*4882a593Smuzhiyun #include <media/v4l2-event.h>
50*4882a593Smuzhiyun #include <media/v4l2-fwnode.h>
51*4882a593Smuzhiyun #include <media/tc35874x.h>
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #include "tc35874x_regs.h"
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static int debug;
56*4882a593Smuzhiyun module_param(debug, int, 0644);
57*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "debug level (0-3)");
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun MODULE_DESCRIPTION("Toshiba TC35874X HDMI to CSI-2 bridge driver");
60*4882a593Smuzhiyun MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>");
61*4882a593Smuzhiyun MODULE_AUTHOR("Mikhail Khelik <mkhelik@cisco.com>");
62*4882a593Smuzhiyun MODULE_AUTHOR("Mats Randgaard <matrandg@cisco.com>");
63*4882a593Smuzhiyun MODULE_LICENSE("GPL");
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x1)
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define EDID_NUM_BLOCKS_MAX 8
68*4882a593Smuzhiyun #define EDID_BLOCK_SIZE 128
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define I2C_MAX_XFER_SIZE  (EDID_BLOCK_SIZE + 2)
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define POLL_INTERVAL_CEC_MS	10
73*4882a593Smuzhiyun #define POLL_INTERVAL_MS	1000
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /* PIXEL_RATE = MIPI_FREQ * 2 * lane / 8bit */
76*4882a593Smuzhiyun #define TC35874X_LINK_FREQ_310MHZ	310000000
77*4882a593Smuzhiyun #define TC35874X_PIXEL_RATE_310M	TC35874X_LINK_FREQ_310MHZ
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define TC35874X_NAME			"tc35874x"
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static const s64 link_freq_menu_items[] = {
82*4882a593Smuzhiyun 	TC35874X_LINK_FREQ_310MHZ,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static const struct v4l2_dv_timings_cap tc35874x_timings_cap = {
86*4882a593Smuzhiyun 	.type = V4L2_DV_BT_656_1120,
87*4882a593Smuzhiyun 	/* keep this initialization for compatibility with GCC < 4.4.6 */
88*4882a593Smuzhiyun 	.reserved = { 0 },
89*4882a593Smuzhiyun 	/* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */
90*4882a593Smuzhiyun 	V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 310000000,
91*4882a593Smuzhiyun 			V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
92*4882a593Smuzhiyun 			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
93*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED |
94*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_REDUCED_BLANKING |
95*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_CUSTOM)
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static u8 EDID_1920x1080_60[] = {
99*4882a593Smuzhiyun 	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
100*4882a593Smuzhiyun 	0x52, 0x62, 0x01, 0x88, 0x00, 0x88, 0x88, 0x88,
101*4882a593Smuzhiyun 	0x1C, 0x15, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
102*4882a593Smuzhiyun 	0x0A, 0x0D, 0xC9, 0xA0, 0x57, 0x47, 0x98, 0x27,
103*4882a593Smuzhiyun 	0x12, 0x48, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x01,
104*4882a593Smuzhiyun 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
105*4882a593Smuzhiyun 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
106*4882a593Smuzhiyun 	0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
107*4882a593Smuzhiyun 	0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E,
108*4882a593Smuzhiyun 	0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20,
109*4882a593Smuzhiyun 	0x6E, 0x28, 0x55, 0x00, 0xC4, 0x8E, 0x21, 0x00,
110*4882a593Smuzhiyun 	0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x54,
111*4882a593Smuzhiyun 	0x37, 0x34, 0x39, 0x2D, 0x66, 0x48, 0x44, 0x37,
112*4882a593Smuzhiyun 	0x32, 0x30, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD,
113*4882a593Smuzhiyun 	0x00, 0x14, 0x78, 0x01, 0xFF, 0x1D, 0x00, 0x0A,
114*4882a593Smuzhiyun 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x7B,
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static u8 EDID_extend[] = {
118*4882a593Smuzhiyun 	0x02, 0x03, 0x1A, 0x71, 0x47, 0x90, 0x04, 0x02,
119*4882a593Smuzhiyun 	0x01, 0x11, 0x22, 0x05, 0x23, 0x09, 0x07, 0x01,
120*4882a593Smuzhiyun 	0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0C, 0x00,
121*4882a593Smuzhiyun 	0x10, 0x00, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0,
122*4882a593Smuzhiyun 	0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0x13, 0x8E,
123*4882a593Smuzhiyun 	0x21, 0x00, 0x00, 0x1E, 0xD8, 0x09, 0x80, 0xA0,
124*4882a593Smuzhiyun 	0x20, 0xE0, 0x2D, 0x10, 0x10, 0x60, 0xA2, 0x00,
125*4882a593Smuzhiyun 	0xC4, 0x8E, 0x21, 0x00, 0x00, 0x18, 0x8C, 0x0A,
126*4882a593Smuzhiyun 	0xD0, 0x90, 0x20, 0x40, 0x31, 0x20, 0x0C, 0x40,
127*4882a593Smuzhiyun 	0x55, 0x00, 0x48, 0x39, 0x00, 0x00, 0x00, 0x18,
128*4882a593Smuzhiyun 	0x01, 0x1D, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40,
129*4882a593Smuzhiyun 	0x58, 0x2C, 0x45, 0x00, 0xC0, 0x6C, 0x00, 0x00,
130*4882a593Smuzhiyun 	0x00, 0x18, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C,
131*4882a593Smuzhiyun 	0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xC0, 0x6C,
132*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
133*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun struct tc35874x_mode {
137*4882a593Smuzhiyun 	u32 width;
138*4882a593Smuzhiyun 	u32 height;
139*4882a593Smuzhiyun 	struct v4l2_fract max_fps;
140*4882a593Smuzhiyun 	u32 hts_def;
141*4882a593Smuzhiyun 	u32 vts_def;
142*4882a593Smuzhiyun 	u32 exp_def;
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun static const struct tc35874x_mode supported_modes[] = {
146*4882a593Smuzhiyun 	{
147*4882a593Smuzhiyun 		.width = 1920,
148*4882a593Smuzhiyun 		.height = 1080,
149*4882a593Smuzhiyun 		.max_fps = {
150*4882a593Smuzhiyun 			.numerator = 10000,
151*4882a593Smuzhiyun 			.denominator = 600000,
152*4882a593Smuzhiyun 		},
153*4882a593Smuzhiyun 		.exp_def = 0x470,
154*4882a593Smuzhiyun 		.hts_def = 0x898,
155*4882a593Smuzhiyun 		.vts_def = 0x465,
156*4882a593Smuzhiyun 	}, {
157*4882a593Smuzhiyun 		.width = 1280,
158*4882a593Smuzhiyun 		.height = 720,
159*4882a593Smuzhiyun 		.max_fps = {
160*4882a593Smuzhiyun 			.numerator = 10000,
161*4882a593Smuzhiyun 			.denominator = 600000,
162*4882a593Smuzhiyun 		},
163*4882a593Smuzhiyun 		.exp_def = 0x2f0,
164*4882a593Smuzhiyun 		.hts_def = 0x672,
165*4882a593Smuzhiyun 		.vts_def = 0x2ee,
166*4882a593Smuzhiyun 	}, {
167*4882a593Smuzhiyun 		.width = 720,
168*4882a593Smuzhiyun 		.height = 576,
169*4882a593Smuzhiyun 		.max_fps = {
170*4882a593Smuzhiyun 			.numerator = 10000,
171*4882a593Smuzhiyun 			.denominator = 500000,
172*4882a593Smuzhiyun 		},
173*4882a593Smuzhiyun 		.exp_def = 0x275,
174*4882a593Smuzhiyun 		.hts_def = 0x360,
175*4882a593Smuzhiyun 		.vts_def = 0x271,
176*4882a593Smuzhiyun 	}, {
177*4882a593Smuzhiyun 		.width = 720,
178*4882a593Smuzhiyun 		.height = 480,
179*4882a593Smuzhiyun 		.max_fps = {
180*4882a593Smuzhiyun 			.numerator = 10000,
181*4882a593Smuzhiyun 			.denominator = 600000,
182*4882a593Smuzhiyun 		},
183*4882a593Smuzhiyun 		.exp_def = 0x210,
184*4882a593Smuzhiyun 		.hts_def = 0x35a,
185*4882a593Smuzhiyun 		.vts_def = 0x20d,
186*4882a593Smuzhiyun 	},
187*4882a593Smuzhiyun };
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun struct tc35874x_state {
190*4882a593Smuzhiyun 	struct tc35874x_platform_data pdata;
191*4882a593Smuzhiyun 	struct v4l2_fwnode_bus_mipi_csi2 bus;
192*4882a593Smuzhiyun 	struct v4l2_subdev sd;
193*4882a593Smuzhiyun 	struct media_pad pad;
194*4882a593Smuzhiyun 	struct v4l2_ctrl_handler hdl;
195*4882a593Smuzhiyun 	struct i2c_client *i2c_client;
196*4882a593Smuzhiyun 	/* CONFCTL is modified in ops and tc35874x_hdmi_sys_int_handler */
197*4882a593Smuzhiyun 	struct mutex confctl_mutex;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* controls */
200*4882a593Smuzhiyun 	struct v4l2_ctrl *detect_tx_5v_ctrl;
201*4882a593Smuzhiyun 	struct v4l2_ctrl *audio_sampling_rate_ctrl;
202*4882a593Smuzhiyun 	struct v4l2_ctrl *audio_present_ctrl;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	struct delayed_work delayed_work_enable_hotplug;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	struct timer_list timer;
207*4882a593Smuzhiyun 	struct work_struct work_i2c_poll;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	/* edid  */
210*4882a593Smuzhiyun 	u8 edid_blocks_written;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	struct v4l2_dv_timings timings;
213*4882a593Smuzhiyun 	u32 mbus_fmt_code;
214*4882a593Smuzhiyun 	u8 csi_lanes_in_use;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	struct gpio_desc *reset_gpio;
217*4882a593Smuzhiyun 	struct cec_adapter *cec_adap;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	u32 module_index;
220*4882a593Smuzhiyun 	const char *module_facing;
221*4882a593Smuzhiyun 	const char *module_name;
222*4882a593Smuzhiyun 	const char *len_name;
223*4882a593Smuzhiyun 	struct v4l2_ctrl *link_freq;
224*4882a593Smuzhiyun 	struct v4l2_ctrl *pixel_rate;
225*4882a593Smuzhiyun 	const struct tc35874x_mode *cur_mode;
226*4882a593Smuzhiyun };
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun static void tc35874x_enable_interrupts(struct v4l2_subdev *sd,
229*4882a593Smuzhiyun 		bool cable_connected);
230*4882a593Smuzhiyun static int tc35874x_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd);
231*4882a593Smuzhiyun static int tc35874x_s_dv_timings(struct v4l2_subdev *sd,
232*4882a593Smuzhiyun 				 struct v4l2_dv_timings *timings);
233*4882a593Smuzhiyun 
to_state(struct v4l2_subdev * sd)234*4882a593Smuzhiyun static inline struct tc35874x_state *to_state(struct v4l2_subdev *sd)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	return container_of(sd, struct tc35874x_state, sd);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun /* --------------- I2C --------------- */
240*4882a593Smuzhiyun 
i2c_rd(struct v4l2_subdev * sd,u16 reg,u8 * values,u32 n)241*4882a593Smuzhiyun static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
244*4882a593Smuzhiyun 	struct i2c_client *client = state->i2c_client;
245*4882a593Smuzhiyun 	int err;
246*4882a593Smuzhiyun 	u8 buf[2] = { reg >> 8, reg & 0xff };
247*4882a593Smuzhiyun 	struct i2c_msg msgs[] = {
248*4882a593Smuzhiyun 		{
249*4882a593Smuzhiyun 			.addr = client->addr,
250*4882a593Smuzhiyun 			.flags = 0,
251*4882a593Smuzhiyun 			.len = 2,
252*4882a593Smuzhiyun 			.buf = buf,
253*4882a593Smuzhiyun 		},
254*4882a593Smuzhiyun 		{
255*4882a593Smuzhiyun 			.addr = client->addr,
256*4882a593Smuzhiyun 			.flags = I2C_M_RD,
257*4882a593Smuzhiyun 			.len = n,
258*4882a593Smuzhiyun 			.buf = values,
259*4882a593Smuzhiyun 		},
260*4882a593Smuzhiyun 	};
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
263*4882a593Smuzhiyun 	if (err != ARRAY_SIZE(msgs)) {
264*4882a593Smuzhiyun 		v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n",
265*4882a593Smuzhiyun 				__func__, reg, client->addr);
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
i2c_wr(struct v4l2_subdev * sd,u16 reg,u8 * values,u32 n)269*4882a593Smuzhiyun static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
272*4882a593Smuzhiyun 	struct i2c_client *client = state->i2c_client;
273*4882a593Smuzhiyun 	int err, i;
274*4882a593Smuzhiyun 	struct i2c_msg msg;
275*4882a593Smuzhiyun 	u8 data[I2C_MAX_XFER_SIZE];
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if ((2 + n) > I2C_MAX_XFER_SIZE) {
278*4882a593Smuzhiyun 		n = I2C_MAX_XFER_SIZE - 2;
279*4882a593Smuzhiyun 		v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n",
280*4882a593Smuzhiyun 			  reg, 2 + n);
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	msg.addr = client->addr;
284*4882a593Smuzhiyun 	msg.buf = data;
285*4882a593Smuzhiyun 	msg.len = 2 + n;
286*4882a593Smuzhiyun 	msg.flags = 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	data[0] = reg >> 8;
289*4882a593Smuzhiyun 	data[1] = reg & 0xff;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	for (i = 0; i < n; i++)
292*4882a593Smuzhiyun 		data[2 + i] = values[i];
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, &msg, 1);
295*4882a593Smuzhiyun 	if (err != 1) {
296*4882a593Smuzhiyun 		v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n",
297*4882a593Smuzhiyun 				__func__, reg, client->addr);
298*4882a593Smuzhiyun 		return;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (debug < 3)
302*4882a593Smuzhiyun 		return;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	switch (n) {
305*4882a593Smuzhiyun 	case 1:
306*4882a593Smuzhiyun 		v4l2_info(sd, "I2C write 0x%04x = 0x%02x\n",
307*4882a593Smuzhiyun 				reg, data[2]);
308*4882a593Smuzhiyun 		break;
309*4882a593Smuzhiyun 	case 2:
310*4882a593Smuzhiyun 		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x\n",
311*4882a593Smuzhiyun 				reg, data[3], data[2]);
312*4882a593Smuzhiyun 		break;
313*4882a593Smuzhiyun 	case 4:
314*4882a593Smuzhiyun 		v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x\n",
315*4882a593Smuzhiyun 				reg, data[5], data[4], data[3], data[2]);
316*4882a593Smuzhiyun 		break;
317*4882a593Smuzhiyun 	default:
318*4882a593Smuzhiyun 		v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n",
319*4882a593Smuzhiyun 				n, reg);
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
i2c_rdreg(struct v4l2_subdev * sd,u16 reg,u32 n)323*4882a593Smuzhiyun static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	__le32 val = 0;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	i2c_rd(sd, reg, (u8 __force *)&val, n);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	return le32_to_cpu(val);
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
i2c_wrreg(struct v4l2_subdev * sd,u16 reg,u32 val,u32 n)332*4882a593Smuzhiyun static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	__le32 raw = cpu_to_le32(val);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	i2c_wr(sd, reg, (u8 __force *)&raw, n);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
i2c_rd8(struct v4l2_subdev * sd,u16 reg)339*4882a593Smuzhiyun static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	return i2c_rdreg(sd, reg, 1);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
i2c_wr8(struct v4l2_subdev * sd,u16 reg,u8 val)344*4882a593Smuzhiyun static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	i2c_wrreg(sd, reg, val, 1);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
i2c_wr8_and_or(struct v4l2_subdev * sd,u16 reg,u8 mask,u8 val)349*4882a593Smuzhiyun static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
350*4882a593Smuzhiyun 		u8 mask, u8 val)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 1) & mask) | val, 1);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
i2c_rd16(struct v4l2_subdev * sd,u16 reg)355*4882a593Smuzhiyun static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	return i2c_rdreg(sd, reg, 2);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
i2c_wr16(struct v4l2_subdev * sd,u16 reg,u16 val)360*4882a593Smuzhiyun static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	i2c_wrreg(sd, reg, val, 2);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
i2c_wr16_and_or(struct v4l2_subdev * sd,u16 reg,u16 mask,u16 val)365*4882a593Smuzhiyun static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
i2c_rd32(struct v4l2_subdev * sd,u16 reg)370*4882a593Smuzhiyun static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	return i2c_rdreg(sd, reg, 4);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
i2c_wr32(struct v4l2_subdev * sd,u16 reg,u32 val)375*4882a593Smuzhiyun static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	i2c_wrreg(sd, reg, val, 4);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun /* --------------- STATUS --------------- */
381*4882a593Smuzhiyun 
is_hdmi(struct v4l2_subdev * sd)382*4882a593Smuzhiyun static inline bool is_hdmi(struct v4l2_subdev *sd)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
tx_5v_power_present(struct v4l2_subdev * sd)387*4882a593Smuzhiyun static inline bool tx_5v_power_present(struct v4l2_subdev *sd)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
no_signal(struct v4l2_subdev * sd)392*4882a593Smuzhiyun static inline bool no_signal(struct v4l2_subdev *sd)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
no_sync(struct v4l2_subdev * sd)397*4882a593Smuzhiyun static inline bool no_sync(struct v4l2_subdev *sd)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
audio_present(struct v4l2_subdev * sd)402*4882a593Smuzhiyun static inline bool audio_present(struct v4l2_subdev *sd)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun 	return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
get_audio_sampling_rate(struct v4l2_subdev * sd)407*4882a593Smuzhiyun static int get_audio_sampling_rate(struct v4l2_subdev *sd)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	static const int code_to_rate[] = {
410*4882a593Smuzhiyun 		44100, 0, 48000, 32000, 22050, 384000, 24000, 352800,
411*4882a593Smuzhiyun 		88200, 768000, 96000, 705600, 176400, 0, 192000, 0
412*4882a593Smuzhiyun 	};
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/* Register FS_SET is not cleared when the cable is disconnected */
415*4882a593Smuzhiyun 	if (no_signal(sd))
416*4882a593Smuzhiyun 		return 0;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS];
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /* --------------- TIMINGS --------------- */
422*4882a593Smuzhiyun 
fps(const struct v4l2_bt_timings * t)423*4882a593Smuzhiyun static inline unsigned fps(const struct v4l2_bt_timings *t)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t))
426*4882a593Smuzhiyun 		return 0;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	return DIV_ROUND_CLOSEST((unsigned)t->pixelclock,
429*4882a593Smuzhiyun 			V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t));
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
tc35874x_get_detected_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)432*4882a593Smuzhiyun static int tc35874x_get_detected_timings(struct v4l2_subdev *sd,
433*4882a593Smuzhiyun 				     struct v4l2_dv_timings *timings)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct v4l2_bt_timings *bt = &timings->bt;
436*4882a593Smuzhiyun 	unsigned width, height, frame_width, frame_height, frame_interval, fps;
437*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
438*4882a593Smuzhiyun 	u16 fifo_level;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	memset(timings, 0, sizeof(struct v4l2_dv_timings));
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	if (no_signal(sd)) {
443*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__);
444*4882a593Smuzhiyun 		return -ENOLINK;
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun 	if (no_sync(sd)) {
447*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__);
448*4882a593Smuzhiyun 		return -ENOLCK;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	timings->type = V4L2_DV_BT_656_1120;
452*4882a593Smuzhiyun 	bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ?
453*4882a593Smuzhiyun 		V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) +
456*4882a593Smuzhiyun 		i2c_rd8(sd, DE_WIDTH_H_LO);
457*4882a593Smuzhiyun 	height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) +
458*4882a593Smuzhiyun 		i2c_rd8(sd, DE_WIDTH_V_LO);
459*4882a593Smuzhiyun 	frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) +
460*4882a593Smuzhiyun 		i2c_rd8(sd, H_SIZE_LO);
461*4882a593Smuzhiyun 	frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) +
462*4882a593Smuzhiyun 		i2c_rd8(sd, V_SIZE_LO)) / 2;
463*4882a593Smuzhiyun 	/* frame interval in milliseconds * 10
464*4882a593Smuzhiyun 	 * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */
465*4882a593Smuzhiyun 	frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) +
466*4882a593Smuzhiyun 		i2c_rd8(sd, FV_CNT_LO);
467*4882a593Smuzhiyun 	fps = (frame_interval > 0) ?
468*4882a593Smuzhiyun 		DIV_ROUND_CLOSEST(10000, frame_interval) : 0;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	bt->width = width;
471*4882a593Smuzhiyun 	bt->height = height;
472*4882a593Smuzhiyun 	bt->vsync = frame_height - height;
473*4882a593Smuzhiyun 	bt->hsync = frame_width - width;
474*4882a593Smuzhiyun 	bt->pixelclock = frame_width * frame_height * fps;
475*4882a593Smuzhiyun 	if (bt->interlaced == V4L2_DV_INTERLACED) {
476*4882a593Smuzhiyun 		bt->height *= 2;
477*4882a593Smuzhiyun 		bt->il_vsync = bt->vsync + 1;
478*4882a593Smuzhiyun 		bt->pixelclock /= 2;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 		/* frame count number: FS = FE 1,2,1,2... */
481*4882a593Smuzhiyun 		i2c_wr16(sd, FCCTL, 0x0002);
482*4882a593Smuzhiyun 		/* packet id for interlace mode only */
483*4882a593Smuzhiyun 		i2c_wr16(sd, PACKETID1, 0x1e1e);
484*4882a593Smuzhiyun 	} else {
485*4882a593Smuzhiyun 		i2c_wr16(sd, FCCTL, 0);
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	if (state->csi_lanes_in_use == 4) {
489*4882a593Smuzhiyun 		if ((width == 1920 && height == 1080) ||
490*4882a593Smuzhiyun 			(width == 1280 && height == 720)) {
491*4882a593Smuzhiyun 			fifo_level = 370;
492*4882a593Smuzhiyun 		} else if ((width == 720 && height == 576) ||
493*4882a593Smuzhiyun 			(width == 720 && height == 480)) {
494*4882a593Smuzhiyun 			fifo_level = 350;
495*4882a593Smuzhiyun 		} else {
496*4882a593Smuzhiyun 			fifo_level = 300;
497*4882a593Smuzhiyun 		}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 		if ((bt->interlaced == V4L2_DV_INTERLACED) || (fps <= 33))
500*4882a593Smuzhiyun 			fifo_level = 300;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		v4l2_dbg(2, debug, sd, "%s interlaced:%d, fifo_level:%d\n",
503*4882a593Smuzhiyun 			__func__, bt->interlaced, fifo_level);
504*4882a593Smuzhiyun 		i2c_wr16(sd, FIFOCTL, fifo_level);
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	return 0;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun /* --------------- HOTPLUG / HDCP / EDID --------------- */
511*4882a593Smuzhiyun 
tc35874x_delayed_work_enable_hotplug(struct work_struct * work)512*4882a593Smuzhiyun static void tc35874x_delayed_work_enable_hotplug(struct work_struct *work)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	struct delayed_work *dwork = to_delayed_work(work);
515*4882a593Smuzhiyun 	struct tc35874x_state *state = container_of(dwork,
516*4882a593Smuzhiyun 			struct tc35874x_state, delayed_work_enable_hotplug);
517*4882a593Smuzhiyun 	struct v4l2_subdev *sd = &state->sd;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
tc35874x_set_hdmi_hdcp(struct v4l2_subdev * sd,bool enable)524*4882a593Smuzhiyun static void tc35874x_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ?
527*4882a593Smuzhiyun 				"enable" : "disable");
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (enable) {
530*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, KEY_RD_CMD);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION, 0);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, HDCP_REG1, 0xff,
535*4882a593Smuzhiyun 				MASK_AUTH_UNAUTH_SEL_16_FRAMES |
536*4882a593Smuzhiyun 				MASK_AUTH_UNAUTH_AUTO);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET,
539*4882a593Smuzhiyun 				SET_AUTO_P3_RESET_FRAMES(0x0f));
540*4882a593Smuzhiyun 	} else {
541*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION,
542*4882a593Smuzhiyun 				MASK_MANUAL_AUTHENTICATION);
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
tc35874x_disable_edid(struct v4l2_subdev * sd)546*4882a593Smuzhiyun static void tc35874x_disable_edid(struct v4l2_subdev *sd)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	/* DDC access to EDID is also disabled when hotplug is disabled. See
555*4882a593Smuzhiyun 	 * register DDC_CTL */
556*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0);
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
tc35874x_enable_edid(struct v4l2_subdev * sd)559*4882a593Smuzhiyun static void tc35874x_enable_edid(struct v4l2_subdev *sd)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (state->edid_blocks_written == 0) {
564*4882a593Smuzhiyun 		v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__);
565*4882a593Smuzhiyun 		tc35874x_s_ctrl_detect_tx_5v(sd);
566*4882a593Smuzhiyun 		return;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s:\n", __func__);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	/* Enable hotplug after 100 ms. DDC access to EDID is also enabled when
572*4882a593Smuzhiyun 	 * hotplug is enabled. See register DDC_CTL */
573*4882a593Smuzhiyun 	schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	tc35874x_enable_interrupts(sd, true);
576*4882a593Smuzhiyun 	tc35874x_s_ctrl_detect_tx_5v(sd);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
tc35874x_erase_bksv(struct v4l2_subdev * sd)579*4882a593Smuzhiyun static void tc35874x_erase_bksv(struct v4l2_subdev *sd)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	int i;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	for (i = 0; i < 5; i++)
584*4882a593Smuzhiyun 		i2c_wr8(sd, BKSV + i, 0);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun /* --------------- AVI infoframe --------------- */
588*4882a593Smuzhiyun 
print_avi_infoframe(struct v4l2_subdev * sd)589*4882a593Smuzhiyun static void print_avi_infoframe(struct v4l2_subdev *sd)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
592*4882a593Smuzhiyun 	struct device *dev = &client->dev;
593*4882a593Smuzhiyun 	union hdmi_infoframe frame;
594*4882a593Smuzhiyun 	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	if (!is_hdmi(sd)) {
597*4882a593Smuzhiyun 		v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
598*4882a593Smuzhiyun 		return;
599*4882a593Smuzhiyun 	}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
604*4882a593Smuzhiyun 		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
605*4882a593Smuzhiyun 		return;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	hdmi_infoframe_log(KERN_INFO, dev, &frame);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun /* --------------- CTRLS --------------- */
612*4882a593Smuzhiyun 
tc35874x_s_ctrl_detect_tx_5v(struct v4l2_subdev * sd)613*4882a593Smuzhiyun static int tc35874x_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
618*4882a593Smuzhiyun 			tx_5v_power_present(sd));
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
tc35874x_s_ctrl_audio_sampling_rate(struct v4l2_subdev * sd)621*4882a593Smuzhiyun static int tc35874x_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl,
626*4882a593Smuzhiyun 			get_audio_sampling_rate(sd));
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun 
tc35874x_s_ctrl_audio_present(struct v4l2_subdev * sd)629*4882a593Smuzhiyun static int tc35874x_s_ctrl_audio_present(struct v4l2_subdev *sd)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(state->audio_present_ctrl,
634*4882a593Smuzhiyun 			audio_present(sd));
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
tc35874x_update_controls(struct v4l2_subdev * sd)637*4882a593Smuzhiyun static int tc35874x_update_controls(struct v4l2_subdev *sd)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	int ret = 0;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	ret |= tc35874x_s_ctrl_detect_tx_5v(sd);
642*4882a593Smuzhiyun 	ret |= tc35874x_s_ctrl_audio_sampling_rate(sd);
643*4882a593Smuzhiyun 	ret |= tc35874x_s_ctrl_audio_present(sd);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	return ret;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun /* --------------- INIT --------------- */
649*4882a593Smuzhiyun 
tc35874x_reset_phy(struct v4l2_subdev * sd)650*4882a593Smuzhiyun static void tc35874x_reset_phy(struct v4l2_subdev *sd)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0);
655*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL);
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
tc35874x_reset(struct v4l2_subdev * sd,uint16_t mask)658*4882a593Smuzhiyun static void tc35874x_reset(struct v4l2_subdev *sd, uint16_t mask)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	u16 sysctl = i2c_rd16(sd, SYSCTL);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	i2c_wr16(sd, SYSCTL, sysctl | mask);
663*4882a593Smuzhiyun 	i2c_wr16(sd, SYSCTL, sysctl & ~mask);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun 
tc35874x_sleep_mode(struct v4l2_subdev * sd,bool enable)666*4882a593Smuzhiyun static inline void tc35874x_sleep_mode(struct v4l2_subdev *sd, bool enable)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun 	i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP,
669*4882a593Smuzhiyun 			enable ? MASK_SLEEP : 0);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
enable_stream(struct v4l2_subdev * sd,bool enable)672*4882a593Smuzhiyun static inline void enable_stream(struct v4l2_subdev *sd, bool enable)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: %sable\n",
677*4882a593Smuzhiyun 			__func__, enable ? "en" : "dis");
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	if (enable) {
680*4882a593Smuzhiyun 		/* It is critical for CSI receiver to see lane transition
681*4882a593Smuzhiyun 		 * LP11->HS. Set to non-continuous mode to enable clock lane
682*4882a593Smuzhiyun 		 * LP11 state. */
683*4882a593Smuzhiyun 		i2c_wr32(sd, TXOPTIONCNTRL, 0);
684*4882a593Smuzhiyun 		/* Set to continuous mode to trigger LP11->HS transition */
685*4882a593Smuzhiyun 		i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE);
686*4882a593Smuzhiyun 		/* Unmute video */
687*4882a593Smuzhiyun 		i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE);
688*4882a593Smuzhiyun 	} else {
689*4882a593Smuzhiyun 		/* Mute video so that all data lanes go to LSP11 state.
690*4882a593Smuzhiyun 		 * No data is output to CSI Tx block. */
691*4882a593Smuzhiyun 		i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE);
692*4882a593Smuzhiyun 		/* Set to non-continuous mode to enable clock lane LP11 state. */
693*4882a593Smuzhiyun 		i2c_wr32(sd, TXOPTIONCNTRL, 0);
694*4882a593Smuzhiyun 	}
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	mutex_lock(&state->confctl_mutex);
697*4882a593Smuzhiyun 	i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN),
698*4882a593Smuzhiyun 			enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0);
699*4882a593Smuzhiyun 	mutex_unlock(&state->confctl_mutex);
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
tc35874x_set_pll(struct v4l2_subdev * sd)702*4882a593Smuzhiyun static void tc35874x_set_pll(struct v4l2_subdev *sd)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
705*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = &state->pdata;
706*4882a593Smuzhiyun 	u16 pllctl0 = i2c_rd16(sd, PLLCTL0);
707*4882a593Smuzhiyun 	u16 pllctl1 = i2c_rd16(sd, PLLCTL1);
708*4882a593Smuzhiyun 	u16 pllctl0_new;
709*4882a593Smuzhiyun 	u32 hsck;
710*4882a593Smuzhiyun 	u16 pll_frs;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	if (state->csi_lanes_in_use == 4) {
713*4882a593Smuzhiyun 		if ((state->timings.bt.interlaced) ||
714*4882a593Smuzhiyun 			(fps(&(state->timings.bt)) <= 33)) {
715*4882a593Smuzhiyun 			pdata->pll_prd = 2;
716*4882a593Smuzhiyun 			pdata->pll_fbd = 65;
717*4882a593Smuzhiyun 			pll_frs = 0x1;
718*4882a593Smuzhiyun 		} else {
719*4882a593Smuzhiyun 			pdata->pll_prd = 5;
720*4882a593Smuzhiyun 			pdata->pll_fbd = 138;
721*4882a593Smuzhiyun 			pll_frs = 0x0;
722*4882a593Smuzhiyun 		}
723*4882a593Smuzhiyun 	} else {
724*4882a593Smuzhiyun 		hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 		if (state->timings.bt.interlaced)
727*4882a593Smuzhiyun 			hsck /= 2;
728*4882a593Smuzhiyun 		if (hsck > 500000000)
729*4882a593Smuzhiyun 			pll_frs = 0x0;
730*4882a593Smuzhiyun 		else if (hsck > 250000000)
731*4882a593Smuzhiyun 			pll_frs = 0x1;
732*4882a593Smuzhiyun 		else if (hsck > 125000000)
733*4882a593Smuzhiyun 			pll_frs = 0x2;
734*4882a593Smuzhiyun 		else
735*4882a593Smuzhiyun 			pll_frs = 0x3;
736*4882a593Smuzhiyun 	}
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | SET_PLL_FBD(pdata->pll_fbd);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd,
741*4882a593Smuzhiyun 		"%s: prd:%d, fbd:%d, frs:%d, interlaced:%d, fps:%d\n",
742*4882a593Smuzhiyun 		__func__, pdata->pll_prd, pdata->pll_fbd, pll_frs,
743*4882a593Smuzhiyun 		state->timings.bt.interlaced, fps(&(state->timings.bt)));
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	/* Only rewrite when needed (new value or disabled), since rewriting
746*4882a593Smuzhiyun 	 * triggers another format change event. */
747*4882a593Smuzhiyun 	if (pllctl0 != pllctl0_new || (pllctl1 & MASK_PLL_EN) == 0 ||
748*4882a593Smuzhiyun 		SET_PLL_FRS(pll_frs) != (pllctl1 & MASK_PLL_FRS)) {
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__);
751*4882a593Smuzhiyun 		tc35874x_sleep_mode(sd, true);
752*4882a593Smuzhiyun 		i2c_wr16(sd, PLLCTL0, pllctl0_new);
753*4882a593Smuzhiyun 		i2c_wr16_and_or(sd, PLLCTL1,
754*4882a593Smuzhiyun 				~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN),
755*4882a593Smuzhiyun 				(SET_PLL_FRS(pll_frs) | MASK_RESETB |
756*4882a593Smuzhiyun 				 MASK_PLL_EN));
757*4882a593Smuzhiyun 		udelay(10); /* REF_02, Sheet "Source HDMI" */
758*4882a593Smuzhiyun 		i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN);
759*4882a593Smuzhiyun 		tc35874x_sleep_mode(sd, false);
760*4882a593Smuzhiyun 	}
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
tc35874x_set_ref_clk(struct v4l2_subdev * sd)763*4882a593Smuzhiyun static void tc35874x_set_ref_clk(struct v4l2_subdev *sd)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
766*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = &state->pdata;
767*4882a593Smuzhiyun 	u32 sys_freq;
768*4882a593Smuzhiyun 	u32 lockdet_ref;
769*4882a593Smuzhiyun 	u16 fh_min;
770*4882a593Smuzhiyun 	u16 fh_max;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	BUG_ON(!(pdata->refclk_hz == 26000000 ||
773*4882a593Smuzhiyun 		 pdata->refclk_hz == 27000000 ||
774*4882a593Smuzhiyun 		 pdata->refclk_hz == 42000000));
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	sys_freq = pdata->refclk_hz / 10000;
777*4882a593Smuzhiyun 	i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff);
778*4882a593Smuzhiyun 	i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND,
781*4882a593Smuzhiyun 			(pdata->refclk_hz == 42000000) ?
782*4882a593Smuzhiyun 			MASK_PHY_SYSCLK_IND : 0x0);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	fh_min = pdata->refclk_hz / 100000;
785*4882a593Smuzhiyun 	i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff);
786*4882a593Smuzhiyun 	i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	fh_max = (fh_min * 66) / 10;
789*4882a593Smuzhiyun 	i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff);
790*4882a593Smuzhiyun 	i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	lockdet_ref = pdata->refclk_hz / 100;
793*4882a593Smuzhiyun 	i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff);
794*4882a593Smuzhiyun 	i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8);
795*4882a593Smuzhiyun 	i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD,
798*4882a593Smuzhiyun 			(pdata->refclk_hz == 27000000) ?
799*4882a593Smuzhiyun 			MASK_NCO_F0_MOD_27MHZ : 0x0);
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun 
tc35874x_set_csi_color_space(struct v4l2_subdev * sd)802*4882a593Smuzhiyun static void tc35874x_set_csi_color_space(struct v4l2_subdev *sd)
803*4882a593Smuzhiyun {
804*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	switch (state->mbus_fmt_code) {
807*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_2X8:
808*4882a593Smuzhiyun 		v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__);
809*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, VOUT_SET2,
810*4882a593Smuzhiyun 				~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff,
811*4882a593Smuzhiyun 				MASK_SEL422 | MASK_VOUT_422FIL_100);
812*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff,
813*4882a593Smuzhiyun 				MASK_VOUT_COLOR_601_YCBCR_LIMITED);
814*4882a593Smuzhiyun 		mutex_lock(&state->confctl_mutex);
815*4882a593Smuzhiyun 		i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT,
816*4882a593Smuzhiyun 				MASK_YCBCRFMT_422_8_BIT);
817*4882a593Smuzhiyun 		mutex_unlock(&state->confctl_mutex);
818*4882a593Smuzhiyun 		break;
819*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
820*4882a593Smuzhiyun 		v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__);
821*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, VOUT_SET2,
822*4882a593Smuzhiyun 				~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff,
823*4882a593Smuzhiyun 				0x00);
824*4882a593Smuzhiyun 		i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff,
825*4882a593Smuzhiyun 				MASK_VOUT_COLOR_RGB_FULL);
826*4882a593Smuzhiyun 		mutex_lock(&state->confctl_mutex);
827*4882a593Smuzhiyun 		i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0);
828*4882a593Smuzhiyun 		mutex_unlock(&state->confctl_mutex);
829*4882a593Smuzhiyun 		break;
830*4882a593Smuzhiyun 	default:
831*4882a593Smuzhiyun 		v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n",
832*4882a593Smuzhiyun 				__func__, state->mbus_fmt_code);
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun 
tc35874x_set_csi(struct v4l2_subdev * sd)836*4882a593Smuzhiyun static void tc35874x_set_csi(struct v4l2_subdev *sd)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
839*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = &state->pdata;
840*4882a593Smuzhiyun 	unsigned lanes = state->csi_lanes_in_use;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s:\n", __func__);
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	tc35874x_reset(sd, MASK_CTXRST);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	if (lanes < 1)
847*4882a593Smuzhiyun 		i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE);
848*4882a593Smuzhiyun 	if (lanes < 1)
849*4882a593Smuzhiyun 		i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE);
850*4882a593Smuzhiyun 	if (lanes < 2)
851*4882a593Smuzhiyun 		i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE);
852*4882a593Smuzhiyun 	if (lanes < 3)
853*4882a593Smuzhiyun 		i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE);
854*4882a593Smuzhiyun 	if (lanes < 4)
855*4882a593Smuzhiyun 		i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: interlaced:%d, fps:%d\n", __func__,
858*4882a593Smuzhiyun 		state->timings.bt.interlaced, fps(&(state->timings.bt)));
859*4882a593Smuzhiyun 	if (state->csi_lanes_in_use == 4) {
860*4882a593Smuzhiyun 		if ((state->timings.bt.interlaced) ||
861*4882a593Smuzhiyun 			(fps(&(state->timings.bt)) <= 33)) {
862*4882a593Smuzhiyun 			state->pdata.lineinitcnt = 0x7d0;
863*4882a593Smuzhiyun 			state->pdata.lptxtimecnt = 0x002;
864*4882a593Smuzhiyun 			state->pdata.tclk_headercnt = 0x901;
865*4882a593Smuzhiyun 			state->pdata.tclk_trailcnt = 0x00;
866*4882a593Smuzhiyun 			state->pdata.ths_headercnt = 0x02;
867*4882a593Smuzhiyun 			state->pdata.twakeup = 0x32c8;
868*4882a593Smuzhiyun 			state->pdata.tclk_postcnt = 0x006;
869*4882a593Smuzhiyun 			state->pdata.ths_trailcnt = 0x0;
870*4882a593Smuzhiyun 			state->pdata.hstxvregcnt = 5;
871*4882a593Smuzhiyun 		} else {
872*4882a593Smuzhiyun 			state->pdata.lineinitcnt = 0x1770;
873*4882a593Smuzhiyun 			state->pdata.lptxtimecnt = 0x05;
874*4882a593Smuzhiyun 			state->pdata.tclk_headercnt = 0x1505;
875*4882a593Smuzhiyun 			state->pdata.tclk_trailcnt = 0x01;
876*4882a593Smuzhiyun 			state->pdata.ths_headercnt = 0x0105;
877*4882a593Smuzhiyun 			state->pdata.twakeup = 0x332c;
878*4882a593Smuzhiyun 			state->pdata.tclk_postcnt = 0x08;
879*4882a593Smuzhiyun 			state->pdata.ths_trailcnt = 0x02;
880*4882a593Smuzhiyun 			state->pdata.hstxvregcnt = 0x05;
881*4882a593Smuzhiyun 		}
882*4882a593Smuzhiyun 	}
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt);
885*4882a593Smuzhiyun 	i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt);
886*4882a593Smuzhiyun 	i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt);
887*4882a593Smuzhiyun 	i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt);
888*4882a593Smuzhiyun 	i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt);
889*4882a593Smuzhiyun 	i2c_wr32(sd, TWAKEUP, pdata->twakeup);
890*4882a593Smuzhiyun 	i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt);
891*4882a593Smuzhiyun 	i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt);
892*4882a593Smuzhiyun 	i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt);
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	i2c_wr32(sd, HSTXVREGEN,
895*4882a593Smuzhiyun 			((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) |
896*4882a593Smuzhiyun 			((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) |
897*4882a593Smuzhiyun 			((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) |
898*4882a593Smuzhiyun 			((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) |
899*4882a593Smuzhiyun 			((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0));
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags &
902*4882a593Smuzhiyun 		 V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0);
903*4882a593Smuzhiyun 	i2c_wr32(sd, STARTCNTRL, MASK_START);
904*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_START, MASK_STRT);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
907*4882a593Smuzhiyun 			MASK_ADDRESS_CSI_CONTROL |
908*4882a593Smuzhiyun 			MASK_CSI_MODE |
909*4882a593Smuzhiyun 			MASK_TXHSMD |
910*4882a593Smuzhiyun 			((lanes == 4) ? MASK_NOL_4 :
911*4882a593Smuzhiyun 			 (lanes == 3) ? MASK_NOL_3 :
912*4882a593Smuzhiyun 			 (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1));
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
915*4882a593Smuzhiyun 			MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK |
916*4882a593Smuzhiyun 			MASK_WCER | MASK_INER);
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR |
919*4882a593Smuzhiyun 			MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK);
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET |
922*4882a593Smuzhiyun 			MASK_ADDRESS_CSI_INT_ENA | MASK_INTER);
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun 
tc35874x_set_hdmi_phy(struct v4l2_subdev * sd)925*4882a593Smuzhiyun static void tc35874x_set_hdmi_phy(struct v4l2_subdev *sd)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
928*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = &state->pdata;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	/* Default settings from REF_02, sheet "Source HDMI"
931*4882a593Smuzhiyun 	 * and custom settings as platform data */
932*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0);
933*4882a593Smuzhiyun 	i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) |
934*4882a593Smuzhiyun 			SET_FREQ_RANGE_MODE_CYCLES(1));
935*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn,
936*4882a593Smuzhiyun 			(pdata->hdmi_phy_auto_reset_tmds_detected ?
937*4882a593Smuzhiyun 			 MASK_PHY_AUTO_RST2 : 0) |
938*4882a593Smuzhiyun 			(pdata->hdmi_phy_auto_reset_tmds_in_range ?
939*4882a593Smuzhiyun 			 MASK_PHY_AUTO_RST3 : 0) |
940*4882a593Smuzhiyun 			(pdata->hdmi_phy_auto_reset_tmds_valid ?
941*4882a593Smuzhiyun 			 MASK_PHY_AUTO_RST4 : 0));
942*4882a593Smuzhiyun 	i2c_wr8(sd, PHY_BIAS, 0x40);
943*4882a593Smuzhiyun 	i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a));
944*4882a593Smuzhiyun 	i2c_wr8(sd, AVM_CTL, 45);
945*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V,
946*4882a593Smuzhiyun 			pdata->hdmi_detection_delay << 4);
947*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST),
948*4882a593Smuzhiyun 			(pdata->hdmi_phy_auto_reset_hsync_out_of_range ?
949*4882a593Smuzhiyun 			 MASK_H_PI_RST : 0) |
950*4882a593Smuzhiyun 			(pdata->hdmi_phy_auto_reset_vsync_out_of_range ?
951*4882a593Smuzhiyun 			 MASK_V_PI_RST : 0));
952*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY);
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
tc35874x_set_hdmi_audio(struct v4l2_subdev * sd)955*4882a593Smuzhiyun static void tc35874x_set_hdmi_audio(struct v4l2_subdev *sd)
956*4882a593Smuzhiyun {
957*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	/* Default settings from REF_02, sheet "Source HDMI" */
960*4882a593Smuzhiyun 	i2c_wr8(sd, FORCE_MUTE, 0x00);
961*4882a593Smuzhiyun 	i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 |
962*4882a593Smuzhiyun 			MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 |
963*4882a593Smuzhiyun 			MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0);
964*4882a593Smuzhiyun 	i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9);
965*4882a593Smuzhiyun 	i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2);
966*4882a593Smuzhiyun 	i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500));
967*4882a593Smuzhiyun 	i2c_wr8(sd, FS_MUTE, 0x00);
968*4882a593Smuzhiyun 	i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE);
969*4882a593Smuzhiyun 	i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE);
970*4882a593Smuzhiyun 	i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM);
971*4882a593Smuzhiyun 	i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM);
972*4882a593Smuzhiyun 	i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S);
973*4882a593Smuzhiyun 	i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100));
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	mutex_lock(&state->confctl_mutex);
976*4882a593Smuzhiyun 	i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 |
977*4882a593Smuzhiyun 			MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX);
978*4882a593Smuzhiyun 	mutex_unlock(&state->confctl_mutex);
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun 
tc35874x_set_hdmi_info_frame_mode(struct v4l2_subdev * sd)981*4882a593Smuzhiyun static void tc35874x_set_hdmi_info_frame_mode(struct v4l2_subdev *sd)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun 	/* Default settings from REF_02, sheet "Source HDMI" */
984*4882a593Smuzhiyun 	i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE |
985*4882a593Smuzhiyun 			MASK_ACP_INT_MODE | MASK_VS_INT_MODE |
986*4882a593Smuzhiyun 			MASK_SPD_INT_MODE | MASK_MS_INT_MODE |
987*4882a593Smuzhiyun 			MASK_AUD_INT_MODE | MASK_AVI_INT_MODE);
988*4882a593Smuzhiyun 	i2c_wr8(sd, NO_PKT_LIMIT, 0x2c);
989*4882a593Smuzhiyun 	i2c_wr8(sd, NO_PKT_CLR, 0x53);
990*4882a593Smuzhiyun 	i2c_wr8(sd, ERR_PK_LIMIT, 0x01);
991*4882a593Smuzhiyun 	i2c_wr8(sd, NO_PKT_LIMIT2, 0x30);
992*4882a593Smuzhiyun 	i2c_wr8(sd, NO_GDB_LIMIT, 0x10);
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun 
tc35874x_initial_setup(struct v4l2_subdev * sd)995*4882a593Smuzhiyun static void tc35874x_initial_setup(struct v4l2_subdev *sd)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
998*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = &state->pdata;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	/* CEC and IR are not supported by this driver */
1001*4882a593Smuzhiyun 	i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST | MASK_I2SDIS),
1002*4882a593Smuzhiyun 			(MASK_CECRST | MASK_IRRST));
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	tc35874x_reset(sd, MASK_CTXRST | MASK_HDMIRST);
1005*4882a593Smuzhiyun 	tc35874x_sleep_mode(sd, false);
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	i2c_wr16(sd, FIFOCTL, pdata->fifo_level);
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	tc35874x_set_ref_clk(sd);
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE,
1012*4882a593Smuzhiyun 			pdata->ddc5v_delay & MASK_DDC5V_MODE);
1013*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC);
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	tc35874x_set_hdmi_phy(sd);
1016*4882a593Smuzhiyun 	tc35874x_set_hdmi_hdcp(sd, pdata->enable_hdcp);
1017*4882a593Smuzhiyun 	tc35874x_set_hdmi_audio(sd);
1018*4882a593Smuzhiyun 	tc35874x_set_hdmi_info_frame_mode(sd);
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	/* All CE and IT formats are detected as RGB full range in DVI mode */
1021*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0);
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE,
1024*4882a593Smuzhiyun 			MASK_VOUTCOLORMODE_AUTO);
1025*4882a593Smuzhiyun 	i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT);
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun /* --------------- IRQ --------------- */
1029*4882a593Smuzhiyun 
tc35874x_format_change(struct v4l2_subdev * sd)1030*4882a593Smuzhiyun static void tc35874x_format_change(struct v4l2_subdev *sd)
1031*4882a593Smuzhiyun {
1032*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1033*4882a593Smuzhiyun 	struct v4l2_dv_timings timings;
1034*4882a593Smuzhiyun 	const struct v4l2_event tc35874x_ev_fmt = {
1035*4882a593Smuzhiyun 		.type = V4L2_EVENT_SOURCE_CHANGE,
1036*4882a593Smuzhiyun 		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
1037*4882a593Smuzhiyun 	};
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	if (tc35874x_get_detected_timings(sd, &timings)) {
1040*4882a593Smuzhiyun 		enable_stream(sd, false);
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: No signal\n",
1043*4882a593Smuzhiyun 				__func__);
1044*4882a593Smuzhiyun 	} else {
1045*4882a593Smuzhiyun 		if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false)) {
1046*4882a593Smuzhiyun 			enable_stream(sd, false);
1047*4882a593Smuzhiyun 			/* automaticly set timing rather than set by userspace */
1048*4882a593Smuzhiyun 			tc35874x_s_dv_timings(sd, &timings);
1049*4882a593Smuzhiyun 		}
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name,
1052*4882a593Smuzhiyun 				"tc35874x_format_change: New format: ",
1053*4882a593Smuzhiyun 				&timings, false);
1054*4882a593Smuzhiyun 	}
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 	if (sd->devnode)
1057*4882a593Smuzhiyun 		v4l2_subdev_notify_event(sd, &tc35874x_ev_fmt);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun 
tc35874x_init_interrupts(struct v4l2_subdev * sd)1060*4882a593Smuzhiyun static void tc35874x_init_interrupts(struct v4l2_subdev *sd)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun 	u16 i;
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	/* clear interrupt status registers */
1065*4882a593Smuzhiyun 	for (i = SYS_INT; i <= KEY_INT; i++)
1066*4882a593Smuzhiyun 		i2c_wr8(sd, i, 0xff);
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	i2c_wr16(sd, INTSTATUS, 0xffff);
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun 
tc35874x_enable_interrupts(struct v4l2_subdev * sd,bool cable_connected)1071*4882a593Smuzhiyun static void tc35874x_enable_interrupts(struct v4l2_subdev *sd,
1072*4882a593Smuzhiyun 		bool cable_connected)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__,
1075*4882a593Smuzhiyun 			cable_connected);
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	if (cable_connected) {
1078*4882a593Smuzhiyun 		i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET |
1079*4882a593Smuzhiyun 					MASK_M_HDMI_DET) & 0xff);
1080*4882a593Smuzhiyun 		i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG);
1081*4882a593Smuzhiyun 		i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK |
1082*4882a593Smuzhiyun 					MASK_M_AF_UNLOCK) & 0xff);
1083*4882a593Smuzhiyun 		i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END);
1084*4882a593Smuzhiyun 		i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG);
1085*4882a593Smuzhiyun 	} else {
1086*4882a593Smuzhiyun 		i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff);
1087*4882a593Smuzhiyun 		i2c_wr8(sd, CLK_INTM, 0xff);
1088*4882a593Smuzhiyun 		i2c_wr8(sd, CBIT_INTM, 0xff);
1089*4882a593Smuzhiyun 		i2c_wr8(sd, AUDIO_INTM, 0xff);
1090*4882a593Smuzhiyun 		i2c_wr8(sd, MISC_INTM, 0xff);
1091*4882a593Smuzhiyun 	}
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun 
tc35874x_hdmi_audio_int_handler(struct v4l2_subdev * sd,bool * handled)1094*4882a593Smuzhiyun static void tc35874x_hdmi_audio_int_handler(struct v4l2_subdev *sd,
1095*4882a593Smuzhiyun 		bool *handled)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun 	u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM);
1098*4882a593Smuzhiyun 	u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	i2c_wr8(sd, AUDIO_INT, audio_int);
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int);
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	tc35874x_s_ctrl_audio_sampling_rate(sd);
1105*4882a593Smuzhiyun 	tc35874x_s_ctrl_audio_present(sd);
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun 
tc35874x_csi_err_int_handler(struct v4l2_subdev * sd,bool * handled)1108*4882a593Smuzhiyun static void tc35874x_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled)
1109*4882a593Smuzhiyun {
1110*4882a593Smuzhiyun 	v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR));
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER);
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun 
tc35874x_hdmi_misc_int_handler(struct v4l2_subdev * sd,bool * handled)1115*4882a593Smuzhiyun static void tc35874x_hdmi_misc_int_handler(struct v4l2_subdev *sd,
1116*4882a593Smuzhiyun 		bool *handled)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun 	u8 misc_int_mask = i2c_rd8(sd, MISC_INTM);
1119*4882a593Smuzhiyun 	u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask;
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	i2c_wr8(sd, MISC_INT, misc_int);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int);
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	if (misc_int & MASK_I_SYNC_CHG) {
1126*4882a593Smuzhiyun 		/* Reset the HDMI PHY to try to trigger proper lock on the
1127*4882a593Smuzhiyun 		 * incoming video format. Erase BKSV to prevent that old keys
1128*4882a593Smuzhiyun 		 * are used when a new source is connected. */
1129*4882a593Smuzhiyun 		if (no_sync(sd) || no_signal(sd)) {
1130*4882a593Smuzhiyun 			tc35874x_reset_phy(sd);
1131*4882a593Smuzhiyun 			tc35874x_erase_bksv(sd);
1132*4882a593Smuzhiyun 		}
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 		tc35874x_format_change(sd);
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 		misc_int &= ~MASK_I_SYNC_CHG;
1137*4882a593Smuzhiyun 		if (handled)
1138*4882a593Smuzhiyun 			*handled = true;
1139*4882a593Smuzhiyun 	}
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	if (misc_int) {
1142*4882a593Smuzhiyun 		v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n",
1143*4882a593Smuzhiyun 				__func__, misc_int);
1144*4882a593Smuzhiyun 	}
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun 
tc35874x_hdmi_cbit_int_handler(struct v4l2_subdev * sd,bool * handled)1147*4882a593Smuzhiyun static void tc35874x_hdmi_cbit_int_handler(struct v4l2_subdev *sd,
1148*4882a593Smuzhiyun 		bool *handled)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM);
1151*4882a593Smuzhiyun 	u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	i2c_wr8(sd, CBIT_INT, cbit_int);
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int);
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	if (cbit_int & MASK_I_CBIT_FS) {
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n",
1160*4882a593Smuzhiyun 				__func__);
1161*4882a593Smuzhiyun 		tc35874x_s_ctrl_audio_sampling_rate(sd);
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 		cbit_int &= ~MASK_I_CBIT_FS;
1164*4882a593Smuzhiyun 		if (handled)
1165*4882a593Smuzhiyun 			*handled = true;
1166*4882a593Smuzhiyun 	}
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) {
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: Audio present changed\n",
1171*4882a593Smuzhiyun 				__func__);
1172*4882a593Smuzhiyun 		tc35874x_s_ctrl_audio_present(sd);
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 		cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK);
1175*4882a593Smuzhiyun 		if (handled)
1176*4882a593Smuzhiyun 			*handled = true;
1177*4882a593Smuzhiyun 	}
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	if (cbit_int) {
1180*4882a593Smuzhiyun 		v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n",
1181*4882a593Smuzhiyun 				__func__, cbit_int);
1182*4882a593Smuzhiyun 	}
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun 
tc35874x_hdmi_clk_int_handler(struct v4l2_subdev * sd,bool * handled)1185*4882a593Smuzhiyun static void tc35874x_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled)
1186*4882a593Smuzhiyun {
1187*4882a593Smuzhiyun 	u8 clk_int_mask = i2c_rd8(sd, CLK_INTM);
1188*4882a593Smuzhiyun 	u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask;
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	/* Bit 7 and bit 6 are set even when they are masked */
1191*4882a593Smuzhiyun 	i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int);
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	if (clk_int & (MASK_I_IN_DE_CHG)) {
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n",
1198*4882a593Smuzhiyun 				__func__);
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 		/* If the source switch to a new resolution with the same pixel
1201*4882a593Smuzhiyun 		 * frequency as the existing (e.g. 1080p25 -> 720p50), the
1202*4882a593Smuzhiyun 		 * I_SYNC_CHG interrupt is not always triggered, while the
1203*4882a593Smuzhiyun 		 * I_IN_DE_CHG interrupt seems to work fine. Format change
1204*4882a593Smuzhiyun 		 * notifications are only sent when the signal is stable to
1205*4882a593Smuzhiyun 		 * reduce the number of notifications. */
1206*4882a593Smuzhiyun 		if (!no_signal(sd) && !no_sync(sd))
1207*4882a593Smuzhiyun 			tc35874x_format_change(sd);
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 		clk_int &= ~(MASK_I_IN_DE_CHG);
1210*4882a593Smuzhiyun 		if (handled)
1211*4882a593Smuzhiyun 			*handled = true;
1212*4882a593Smuzhiyun 	}
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 	if (clk_int) {
1215*4882a593Smuzhiyun 		v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n",
1216*4882a593Smuzhiyun 				__func__, clk_int);
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun 
tc35874x_hdmi_sys_int_handler(struct v4l2_subdev * sd,bool * handled)1220*4882a593Smuzhiyun static void tc35874x_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1223*4882a593Smuzhiyun 	u8 sys_int_mask = i2c_rd8(sd, SYS_INTM);
1224*4882a593Smuzhiyun 	u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	i2c_wr8(sd, SYS_INT, sys_int);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int);
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	if (sys_int & MASK_I_DDC) {
1231*4882a593Smuzhiyun 		bool tx_5v = tx_5v_power_present(sd);
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n",
1234*4882a593Smuzhiyun 				__func__, tx_5v ?  "yes" : "no");
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 		if (tx_5v) {
1237*4882a593Smuzhiyun 			tc35874x_enable_edid(sd);
1238*4882a593Smuzhiyun 		} else {
1239*4882a593Smuzhiyun 			tc35874x_enable_interrupts(sd, false);
1240*4882a593Smuzhiyun 			tc35874x_disable_edid(sd);
1241*4882a593Smuzhiyun 			memset(&state->timings, 0, sizeof(state->timings));
1242*4882a593Smuzhiyun 			tc35874x_erase_bksv(sd);
1243*4882a593Smuzhiyun 			tc35874x_update_controls(sd);
1244*4882a593Smuzhiyun 		}
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 		sys_int &= ~MASK_I_DDC;
1247*4882a593Smuzhiyun 		if (handled)
1248*4882a593Smuzhiyun 			*handled = true;
1249*4882a593Smuzhiyun 	}
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	if (sys_int & MASK_I_DVI) {
1252*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n",
1253*4882a593Smuzhiyun 				__func__);
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 		/* Reset the HDMI PHY to try to trigger proper lock on the
1256*4882a593Smuzhiyun 		 * incoming video format. Erase BKSV to prevent that old keys
1257*4882a593Smuzhiyun 		 * are used when a new source is connected. */
1258*4882a593Smuzhiyun 		if (no_sync(sd) || no_signal(sd)) {
1259*4882a593Smuzhiyun 			tc35874x_reset_phy(sd);
1260*4882a593Smuzhiyun 			tc35874x_erase_bksv(sd);
1261*4882a593Smuzhiyun 		}
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 		sys_int &= ~MASK_I_DVI;
1264*4882a593Smuzhiyun 		if (handled)
1265*4882a593Smuzhiyun 			*handled = true;
1266*4882a593Smuzhiyun 	}
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	if (sys_int & MASK_I_HDMI) {
1269*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n",
1270*4882a593Smuzhiyun 				__func__);
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 		/* Register is reset in DVI mode (REF_01, c. 6.6.41) */
1273*4882a593Smuzhiyun 		i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON);
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 		sys_int &= ~MASK_I_HDMI;
1276*4882a593Smuzhiyun 		if (handled)
1277*4882a593Smuzhiyun 			*handled = true;
1278*4882a593Smuzhiyun 	}
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	if (sys_int) {
1281*4882a593Smuzhiyun 		v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n",
1282*4882a593Smuzhiyun 				__func__, sys_int);
1283*4882a593Smuzhiyun 	}
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun /* --------------- CTRL OPS --------------- */
1287*4882a593Smuzhiyun 
tc35874x_get_ctrl(struct v4l2_ctrl * ctrl)1288*4882a593Smuzhiyun static int tc35874x_get_ctrl(struct v4l2_ctrl *ctrl)
1289*4882a593Smuzhiyun {
1290*4882a593Smuzhiyun 	int ret = -1;
1291*4882a593Smuzhiyun 	struct tc35874x_state *state = container_of(ctrl->handler,
1292*4882a593Smuzhiyun 			struct tc35874x_state, hdl);
1293*4882a593Smuzhiyun 	struct v4l2_subdev *sd = &(state->sd);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	if (ctrl->id == V4L2_CID_DV_RX_POWER_PRESENT) {
1296*4882a593Smuzhiyun 		ret = tx_5v_power_present(sd);
1297*4882a593Smuzhiyun 		*ctrl->p_new.p_s32 = ret;
1298*4882a593Smuzhiyun 	}
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	return ret;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun /* --------------- CORE OPS --------------- */
1304*4882a593Smuzhiyun 
tc35874x_log_status(struct v4l2_subdev * sd)1305*4882a593Smuzhiyun static int tc35874x_log_status(struct v4l2_subdev *sd)
1306*4882a593Smuzhiyun {
1307*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1308*4882a593Smuzhiyun 	struct v4l2_dv_timings timings;
1309*4882a593Smuzhiyun 	uint8_t hdmi_sys_status =  i2c_rd8(sd, SYS_STATUS);
1310*4882a593Smuzhiyun 	uint16_t sysctl = i2c_rd16(sd, SYSCTL);
1311*4882a593Smuzhiyun 	u8 vi_status3 =  i2c_rd8(sd, VI_STATUS3);
1312*4882a593Smuzhiyun 	const int deep_color_mode[4] = { 8, 10, 12, 16 };
1313*4882a593Smuzhiyun 	static const char * const input_color_space[] = {
1314*4882a593Smuzhiyun 		"RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)",
1315*4882a593Smuzhiyun 		"xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601",
1316*4882a593Smuzhiyun 		"NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"};
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	v4l2_info(sd, "-----Chip status-----\n");
1319*4882a593Smuzhiyun 	v4l2_info(sd, "Chip ID: 0x%02x\n",
1320*4882a593Smuzhiyun 			(i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8);
1321*4882a593Smuzhiyun 	v4l2_info(sd, "Chip revision: 0x%02x\n",
1322*4882a593Smuzhiyun 			i2c_rd16(sd, CHIPID) & MASK_REVID);
1323*4882a593Smuzhiyun 	v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n",
1324*4882a593Smuzhiyun 			!!(sysctl & MASK_IRRST),
1325*4882a593Smuzhiyun 			!!(sysctl & MASK_CECRST),
1326*4882a593Smuzhiyun 			!!(sysctl & MASK_CTXRST),
1327*4882a593Smuzhiyun 			!!(sysctl & MASK_HDMIRST));
1328*4882a593Smuzhiyun 	v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off");
1329*4882a593Smuzhiyun 	v4l2_info(sd, "Cable detected (+5V power): %s\n",
1330*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no");
1331*4882a593Smuzhiyun 	v4l2_info(sd, "DDC lines enabled: %s\n",
1332*4882a593Smuzhiyun 			(i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ?
1333*4882a593Smuzhiyun 			"yes" : "no");
1334*4882a593Smuzhiyun 	v4l2_info(sd, "Hotplug enabled: %s\n",
1335*4882a593Smuzhiyun 			(i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ?
1336*4882a593Smuzhiyun 			"yes" : "no");
1337*4882a593Smuzhiyun 	v4l2_info(sd, "CEC enabled: %s\n",
1338*4882a593Smuzhiyun 			(i2c_rd16(sd, CECEN) & MASK_CECEN) ?  "yes" : "no");
1339*4882a593Smuzhiyun 	v4l2_info(sd, "-----Signal status-----\n");
1340*4882a593Smuzhiyun 	v4l2_info(sd, "TMDS signal detected: %s\n",
1341*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_TMDS ? "yes" : "no");
1342*4882a593Smuzhiyun 	v4l2_info(sd, "Stable sync signal: %s\n",
1343*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_SYNC ? "yes" : "no");
1344*4882a593Smuzhiyun 	v4l2_info(sd, "PHY PLL locked: %s\n",
1345*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no");
1346*4882a593Smuzhiyun 	v4l2_info(sd, "PHY DE detected: %s\n",
1347*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no");
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	if (tc35874x_get_detected_timings(sd, &timings)) {
1350*4882a593Smuzhiyun 		v4l2_info(sd, "No video detected\n");
1351*4882a593Smuzhiyun 	} else {
1352*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name, "Detected format: ", &timings,
1353*4882a593Smuzhiyun 				true);
1354*4882a593Smuzhiyun 	}
1355*4882a593Smuzhiyun 	v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings,
1356*4882a593Smuzhiyun 			true);
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 	v4l2_info(sd, "-----CSI-TX status-----\n");
1359*4882a593Smuzhiyun 	v4l2_info(sd, "Lanes in use: %d\n",
1360*4882a593Smuzhiyun 			state->csi_lanes_in_use);
1361*4882a593Smuzhiyun 	v4l2_info(sd, "Waiting for particular sync signal: %s\n",
1362*4882a593Smuzhiyun 			(i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ?
1363*4882a593Smuzhiyun 			"yes" : "no");
1364*4882a593Smuzhiyun 	v4l2_info(sd, "Transmit mode: %s\n",
1365*4882a593Smuzhiyun 			(i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ?
1366*4882a593Smuzhiyun 			"yes" : "no");
1367*4882a593Smuzhiyun 	v4l2_info(sd, "Receive mode: %s\n",
1368*4882a593Smuzhiyun 			(i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ?
1369*4882a593Smuzhiyun 			"yes" : "no");
1370*4882a593Smuzhiyun 	v4l2_info(sd, "Stopped: %s\n",
1371*4882a593Smuzhiyun 			(i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ?
1372*4882a593Smuzhiyun 			"yes" : "no");
1373*4882a593Smuzhiyun 	v4l2_info(sd, "Color space: %s\n",
1374*4882a593Smuzhiyun 			state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_2X8 ?
1375*4882a593Smuzhiyun 			"YCbCr 422 16-bit" :
1376*4882a593Smuzhiyun 			state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ?
1377*4882a593Smuzhiyun 			"RGB 888 24-bit" : "Unsupported");
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D");
1380*4882a593Smuzhiyun 	v4l2_info(sd, "HDCP encrypted content: %s\n",
1381*4882a593Smuzhiyun 			hdmi_sys_status & MASK_S_HDCP ? "yes" : "no");
1382*4882a593Smuzhiyun 	v4l2_info(sd, "Input color space: %s %s range\n",
1383*4882a593Smuzhiyun 			input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1],
1384*4882a593Smuzhiyun 			(vi_status3 & MASK_LIMITED) ? "limited" : "full");
1385*4882a593Smuzhiyun 	if (!is_hdmi(sd))
1386*4882a593Smuzhiyun 		return 0;
1387*4882a593Smuzhiyun 	v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" :
1388*4882a593Smuzhiyun 			"off");
1389*4882a593Smuzhiyun 	v4l2_info(sd, "Deep color mode: %d-bits per channel\n",
1390*4882a593Smuzhiyun 			deep_color_mode[(i2c_rd8(sd, VI_STATUS1) &
1391*4882a593Smuzhiyun 				MASK_S_DEEPCOLOR) >> 2]);
1392*4882a593Smuzhiyun 	print_avi_infoframe(sd);
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun 	return 0;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
tc35874x_print_register_map(struct v4l2_subdev * sd)1398*4882a593Smuzhiyun static void tc35874x_print_register_map(struct v4l2_subdev *sd)
1399*4882a593Smuzhiyun {
1400*4882a593Smuzhiyun 	v4l2_info(sd, "0x0000-0x00FF: Global Control Register\n");
1401*4882a593Smuzhiyun 	v4l2_info(sd, "0x0100-0x01FF: CSI2-TX PHY Register\n");
1402*4882a593Smuzhiyun 	v4l2_info(sd, "0x0200-0x03FF: CSI2-TX PPI Register\n");
1403*4882a593Smuzhiyun 	v4l2_info(sd, "0x0400-0x05FF: Reserved\n");
1404*4882a593Smuzhiyun 	v4l2_info(sd, "0x0600-0x06FF: CEC Register\n");
1405*4882a593Smuzhiyun 	v4l2_info(sd, "0x0700-0x84FF: Reserved\n");
1406*4882a593Smuzhiyun 	v4l2_info(sd, "0x8500-0x85FF: HDMIRX System Control Register\n");
1407*4882a593Smuzhiyun 	v4l2_info(sd, "0x8600-0x86FF: HDMIRX Audio Control Register\n");
1408*4882a593Smuzhiyun 	v4l2_info(sd, "0x8700-0x87FF: HDMIRX InfoFrame packet data Register\n");
1409*4882a593Smuzhiyun 	v4l2_info(sd, "0x8800-0x88FF: HDMIRX HDCP Port Register\n");
1410*4882a593Smuzhiyun 	v4l2_info(sd, "0x8900-0x89FF: HDMIRX Video Output Port & 3D Register\n");
1411*4882a593Smuzhiyun 	v4l2_info(sd, "0x8A00-0x8BFF: Reserved\n");
1412*4882a593Smuzhiyun 	v4l2_info(sd, "0x8C00-0x8FFF: HDMIRX EDID-RAM (1024bytes)\n");
1413*4882a593Smuzhiyun 	v4l2_info(sd, "0x9000-0x90FF: HDMIRX GBD Extraction Control\n");
1414*4882a593Smuzhiyun 	v4l2_info(sd, "0x9100-0x92FF: HDMIRX GBD RAM read\n");
1415*4882a593Smuzhiyun 	v4l2_info(sd, "0x9300-      : Reserved\n");
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun 
tc35874x_get_reg_size(u16 address)1418*4882a593Smuzhiyun static int tc35874x_get_reg_size(u16 address)
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun 	/* REF_01 p. 66-72 */
1421*4882a593Smuzhiyun 	if (address <= 0x00ff)
1422*4882a593Smuzhiyun 		return 2;
1423*4882a593Smuzhiyun 	else if ((address >= 0x0100) && (address <= 0x06FF))
1424*4882a593Smuzhiyun 		return 4;
1425*4882a593Smuzhiyun 	else if ((address >= 0x0700) && (address <= 0x84ff))
1426*4882a593Smuzhiyun 		return 2;
1427*4882a593Smuzhiyun 	else
1428*4882a593Smuzhiyun 		return 1;
1429*4882a593Smuzhiyun }
1430*4882a593Smuzhiyun 
tc35874x_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)1431*4882a593Smuzhiyun static int tc35874x_g_register(struct v4l2_subdev *sd,
1432*4882a593Smuzhiyun 			       struct v4l2_dbg_register *reg)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun 	if (reg->reg > 0xffff) {
1435*4882a593Smuzhiyun 		tc35874x_print_register_map(sd);
1436*4882a593Smuzhiyun 		return -EINVAL;
1437*4882a593Smuzhiyun 	}
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	reg->size = tc35874x_get_reg_size(reg->reg);
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	reg->val = i2c_rdreg(sd, reg->reg, reg->size);
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun 	return 0;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun 
tc35874x_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)1446*4882a593Smuzhiyun static int tc35874x_s_register(struct v4l2_subdev *sd,
1447*4882a593Smuzhiyun 			       const struct v4l2_dbg_register *reg)
1448*4882a593Smuzhiyun {
1449*4882a593Smuzhiyun 	if (reg->reg > 0xffff) {
1450*4882a593Smuzhiyun 		tc35874x_print_register_map(sd);
1451*4882a593Smuzhiyun 		return -EINVAL;
1452*4882a593Smuzhiyun 	}
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	/* It should not be possible for the user to enable HDCP with a simple
1455*4882a593Smuzhiyun 	 * v4l2-dbg command.
1456*4882a593Smuzhiyun 	 *
1457*4882a593Smuzhiyun 	 * DO NOT REMOVE THIS unless all other issues with HDCP have been
1458*4882a593Smuzhiyun 	 * resolved.
1459*4882a593Smuzhiyun 	 */
1460*4882a593Smuzhiyun 	if (reg->reg == HDCP_MODE ||
1461*4882a593Smuzhiyun 	    reg->reg == HDCP_REG1 ||
1462*4882a593Smuzhiyun 	    reg->reg == HDCP_REG2 ||
1463*4882a593Smuzhiyun 	    reg->reg == HDCP_REG3 ||
1464*4882a593Smuzhiyun 	    reg->reg == BCAPS)
1465*4882a593Smuzhiyun 		return 0;
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 	i2c_wrreg(sd, (u16)reg->reg, reg->val,
1468*4882a593Smuzhiyun 			tc35874x_get_reg_size(reg->reg));
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	return 0;
1471*4882a593Smuzhiyun }
1472*4882a593Smuzhiyun #endif
1473*4882a593Smuzhiyun 
tc35874x_isr(struct v4l2_subdev * sd,u32 status,bool * handled)1474*4882a593Smuzhiyun static int tc35874x_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
1475*4882a593Smuzhiyun {
1476*4882a593Smuzhiyun 	u16 intstatus = i2c_rd16(sd, INTSTATUS);
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus);
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	if (intstatus & MASK_HDMI_INT) {
1481*4882a593Smuzhiyun 		u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0);
1482*4882a593Smuzhiyun 		u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1);
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 		if (hdmi_int0 & MASK_I_MISC)
1485*4882a593Smuzhiyun 			tc35874x_hdmi_misc_int_handler(sd, handled);
1486*4882a593Smuzhiyun 		if (hdmi_int1 & MASK_I_CBIT)
1487*4882a593Smuzhiyun 			tc35874x_hdmi_cbit_int_handler(sd, handled);
1488*4882a593Smuzhiyun 		if (hdmi_int1 & MASK_I_CLK)
1489*4882a593Smuzhiyun 			tc35874x_hdmi_clk_int_handler(sd, handled);
1490*4882a593Smuzhiyun 		if (hdmi_int1 & MASK_I_SYS)
1491*4882a593Smuzhiyun 			tc35874x_hdmi_sys_int_handler(sd, handled);
1492*4882a593Smuzhiyun 		if (hdmi_int1 & MASK_I_AUD)
1493*4882a593Smuzhiyun 			tc35874x_hdmi_audio_int_handler(sd, handled);
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 		i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT);
1496*4882a593Smuzhiyun 		intstatus &= ~MASK_HDMI_INT;
1497*4882a593Smuzhiyun 	}
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	if (intstatus & MASK_CSI_INT) {
1500*4882a593Smuzhiyun 		u32 csi_int = i2c_rd32(sd, CSI_INT);
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 		if (csi_int & MASK_INTER)
1503*4882a593Smuzhiyun 			tc35874x_csi_err_int_handler(sd, handled);
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun 		i2c_wr16(sd, INTSTATUS, MASK_CSI_INT);
1506*4882a593Smuzhiyun 	}
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	intstatus = i2c_rd16(sd, INTSTATUS);
1509*4882a593Smuzhiyun 	if (intstatus) {
1510*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd,
1511*4882a593Smuzhiyun 				"%s: Unhandled IntStatus interrupts: 0x%02x\n",
1512*4882a593Smuzhiyun 				__func__, intstatus);
1513*4882a593Smuzhiyun 	}
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	return 0;
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun 
tc35874x_irq_handler(int irq,void * dev_id)1518*4882a593Smuzhiyun static irqreturn_t tc35874x_irq_handler(int irq, void *dev_id)
1519*4882a593Smuzhiyun {
1520*4882a593Smuzhiyun 	struct tc35874x_state *state = dev_id;
1521*4882a593Smuzhiyun 	bool handled = false;
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	tc35874x_isr(&state->sd, 0, &handled);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 	return handled ? IRQ_HANDLED : IRQ_NONE;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun 
tc35874x_irq_poll_timer(struct timer_list * t)1528*4882a593Smuzhiyun static void tc35874x_irq_poll_timer(struct timer_list *t)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun 	struct tc35874x_state *state = from_timer(state, t, timer);
1531*4882a593Smuzhiyun 	unsigned int msecs;
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	schedule_work(&state->work_i2c_poll);
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	/*
1536*4882a593Smuzhiyun 	 * If CEC is present, then we need to poll more frequently,
1537*4882a593Smuzhiyun 	 * otherwise we will miss CEC messages.
1538*4882a593Smuzhiyun 	 */
1539*4882a593Smuzhiyun 	msecs = state->cec_adap ? POLL_INTERVAL_CEC_MS : POLL_INTERVAL_MS;
1540*4882a593Smuzhiyun 	mod_timer(&state->timer, jiffies + msecs_to_jiffies(msecs));
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun 
tc35874x_work_i2c_poll(struct work_struct * work)1543*4882a593Smuzhiyun static void tc35874x_work_i2c_poll(struct work_struct *work)
1544*4882a593Smuzhiyun {
1545*4882a593Smuzhiyun 	struct tc35874x_state *state = container_of(work,
1546*4882a593Smuzhiyun 			struct tc35874x_state, work_i2c_poll);
1547*4882a593Smuzhiyun 	bool handled;
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 	tc35874x_isr(&state->sd, 0, &handled);
1550*4882a593Smuzhiyun }
1551*4882a593Smuzhiyun 
tc35874x_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)1552*4882a593Smuzhiyun static int tc35874x_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
1553*4882a593Smuzhiyun 				    struct v4l2_event_subscription *sub)
1554*4882a593Smuzhiyun {
1555*4882a593Smuzhiyun 	switch (sub->type) {
1556*4882a593Smuzhiyun 	case V4L2_EVENT_SOURCE_CHANGE:
1557*4882a593Smuzhiyun 		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
1558*4882a593Smuzhiyun 	case V4L2_EVENT_CTRL:
1559*4882a593Smuzhiyun 		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
1560*4882a593Smuzhiyun 	default:
1561*4882a593Smuzhiyun 		return -EINVAL;
1562*4882a593Smuzhiyun 	}
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun /* --------------- VIDEO OPS --------------- */
1566*4882a593Smuzhiyun 
tc35874x_g_input_status(struct v4l2_subdev * sd,u32 * status)1567*4882a593Smuzhiyun static int tc35874x_g_input_status(struct v4l2_subdev *sd, u32 *status)
1568*4882a593Smuzhiyun {
1569*4882a593Smuzhiyun 	*status = 0;
1570*4882a593Smuzhiyun 	*status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
1571*4882a593Smuzhiyun 	*status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0;
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	return 0;
1576*4882a593Smuzhiyun }
1577*4882a593Smuzhiyun 
tc35874x_s_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)1578*4882a593Smuzhiyun static int tc35874x_s_dv_timings(struct v4l2_subdev *sd,
1579*4882a593Smuzhiyun 				 struct v4l2_dv_timings *timings)
1580*4882a593Smuzhiyun {
1581*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	if (!timings)
1584*4882a593Smuzhiyun 		return -EINVAL;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	if (debug)
1587*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name, "tc35874x_s_dv_timings: ",
1588*4882a593Smuzhiyun 				timings, false);
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
1591*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
1592*4882a593Smuzhiyun 		return 0;
1593*4882a593Smuzhiyun 	}
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 	if (!v4l2_valid_dv_timings(timings,
1596*4882a593Smuzhiyun 				&tc35874x_timings_cap, NULL, NULL)) {
1597*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
1598*4882a593Smuzhiyun 		return -ERANGE;
1599*4882a593Smuzhiyun 	}
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	state->timings = *timings;
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	enable_stream(sd, false);
1604*4882a593Smuzhiyun 	tc35874x_set_pll(sd);
1605*4882a593Smuzhiyun 	tc35874x_set_csi(sd);
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 	return 0;
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun 
tc35874x_g_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)1610*4882a593Smuzhiyun static int tc35874x_g_dv_timings(struct v4l2_subdev *sd,
1611*4882a593Smuzhiyun 				 struct v4l2_dv_timings *timings)
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	*timings = state->timings;
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	return 0;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun 
tc35874x_enum_dv_timings(struct v4l2_subdev * sd,struct v4l2_enum_dv_timings * timings)1620*4882a593Smuzhiyun static int tc35874x_enum_dv_timings(struct v4l2_subdev *sd,
1621*4882a593Smuzhiyun 				    struct v4l2_enum_dv_timings *timings)
1622*4882a593Smuzhiyun {
1623*4882a593Smuzhiyun 	if (timings->pad != 0)
1624*4882a593Smuzhiyun 		return -EINVAL;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	return v4l2_enum_dv_timings_cap(timings,
1627*4882a593Smuzhiyun 			&tc35874x_timings_cap, NULL, NULL);
1628*4882a593Smuzhiyun }
1629*4882a593Smuzhiyun 
tc35874x_query_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)1630*4882a593Smuzhiyun static int tc35874x_query_dv_timings(struct v4l2_subdev *sd,
1631*4882a593Smuzhiyun 		struct v4l2_dv_timings *timings)
1632*4882a593Smuzhiyun {
1633*4882a593Smuzhiyun 	int ret;
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	ret = tc35874x_get_detected_timings(sd, timings);
1636*4882a593Smuzhiyun 	if (ret)
1637*4882a593Smuzhiyun 		return ret;
1638*4882a593Smuzhiyun 
1639*4882a593Smuzhiyun 	if (debug)
1640*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name, "tc35874x_query_dv_timings: ",
1641*4882a593Smuzhiyun 				timings, false);
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 	if (!v4l2_valid_dv_timings(timings,
1644*4882a593Smuzhiyun 				&tc35874x_timings_cap, NULL, NULL)) {
1645*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
1646*4882a593Smuzhiyun 		return -ERANGE;
1647*4882a593Smuzhiyun 	}
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 	return 0;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun 
tc35874x_dv_timings_cap(struct v4l2_subdev * sd,struct v4l2_dv_timings_cap * cap)1652*4882a593Smuzhiyun static int tc35874x_dv_timings_cap(struct v4l2_subdev *sd,
1653*4882a593Smuzhiyun 		struct v4l2_dv_timings_cap *cap)
1654*4882a593Smuzhiyun {
1655*4882a593Smuzhiyun 	if (cap->pad != 0)
1656*4882a593Smuzhiyun 		return -EINVAL;
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 	*cap = tc35874x_timings_cap;
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	return 0;
1661*4882a593Smuzhiyun }
1662*4882a593Smuzhiyun 
tc35874x_g_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)1663*4882a593Smuzhiyun static int tc35874x_g_mbus_config(struct v4l2_subdev *sd,
1664*4882a593Smuzhiyun 				 unsigned int pad, struct v4l2_mbus_config *cfg)
1665*4882a593Smuzhiyun {
1666*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	cfg->type = V4L2_MBUS_CSI2_DPHY;
1669*4882a593Smuzhiyun 
1670*4882a593Smuzhiyun 	/* Support for non-continuous CSI-2 clock is missing in the driver */
1671*4882a593Smuzhiyun 	cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	switch (state->csi_lanes_in_use) {
1674*4882a593Smuzhiyun 	case 1:
1675*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
1676*4882a593Smuzhiyun 		break;
1677*4882a593Smuzhiyun 	case 2:
1678*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
1679*4882a593Smuzhiyun 		break;
1680*4882a593Smuzhiyun 	case 3:
1681*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
1682*4882a593Smuzhiyun 		break;
1683*4882a593Smuzhiyun 	case 4:
1684*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
1685*4882a593Smuzhiyun 		break;
1686*4882a593Smuzhiyun 	default:
1687*4882a593Smuzhiyun 		return -EINVAL;
1688*4882a593Smuzhiyun 	}
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	return 0;
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun 
tc35874x_s_stream(struct v4l2_subdev * sd,int enable)1693*4882a593Smuzhiyun static int tc35874x_s_stream(struct v4l2_subdev *sd, int enable)
1694*4882a593Smuzhiyun {
1695*4882a593Smuzhiyun 	enable_stream(sd, enable);
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	/* stop stream to reset csi*/
1698*4882a593Smuzhiyun 	if (!enable)
1699*4882a593Smuzhiyun 		tc35874x_set_csi(sd);
1700*4882a593Smuzhiyun 	return 0;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun /* --------------- PAD OPS --------------- */
1704*4882a593Smuzhiyun 
tc35874x_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)1705*4882a593Smuzhiyun static int tc35874x_enum_mbus_code(struct v4l2_subdev *sd,
1706*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
1707*4882a593Smuzhiyun 		struct v4l2_subdev_mbus_code_enum *code)
1708*4882a593Smuzhiyun {
1709*4882a593Smuzhiyun 	switch (code->index) {
1710*4882a593Smuzhiyun 	case 0:
1711*4882a593Smuzhiyun 		code->code = MEDIA_BUS_FMT_UYVY8_2X8;
1712*4882a593Smuzhiyun 		break;
1713*4882a593Smuzhiyun 	/*
1714*4882a593Smuzhiyun 	case 1:
1715*4882a593Smuzhiyun 		code->code = MEDIA_BUS_FMT_RGB888_1X24;
1716*4882a593Smuzhiyun 		break;
1717*4882a593Smuzhiyun 	*/
1718*4882a593Smuzhiyun 	default:
1719*4882a593Smuzhiyun 		return -EINVAL;
1720*4882a593Smuzhiyun 	}
1721*4882a593Smuzhiyun 	return 0;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun 
tc35874x_enum_frame_sizes(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)1724*4882a593Smuzhiyun static int tc35874x_enum_frame_sizes(struct v4l2_subdev *sd,
1725*4882a593Smuzhiyun 				   struct v4l2_subdev_pad_config *cfg,
1726*4882a593Smuzhiyun 				   struct v4l2_subdev_frame_size_enum *fse)
1727*4882a593Smuzhiyun {
1728*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun 	if (fse->index >= ARRAY_SIZE(supported_modes))
1731*4882a593Smuzhiyun 		return -EINVAL;
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun 	if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
1734*4882a593Smuzhiyun 		return -EINVAL;
1735*4882a593Smuzhiyun 
1736*4882a593Smuzhiyun 	fse->min_width  = supported_modes[fse->index].width;
1737*4882a593Smuzhiyun 	fse->max_width  = supported_modes[fse->index].width;
1738*4882a593Smuzhiyun 	fse->max_height = supported_modes[fse->index].height;
1739*4882a593Smuzhiyun 	fse->min_height = supported_modes[fse->index].height;
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	return 0;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun 
tc35874x_enum_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_interval_enum * fie)1744*4882a593Smuzhiyun static int tc35874x_enum_frame_interval(struct v4l2_subdev *sd,
1745*4882a593Smuzhiyun 				struct v4l2_subdev_pad_config *cfg,
1746*4882a593Smuzhiyun 				struct v4l2_subdev_frame_interval_enum *fie)
1747*4882a593Smuzhiyun {
1748*4882a593Smuzhiyun 	if (fie->index >= ARRAY_SIZE(supported_modes))
1749*4882a593Smuzhiyun 		return -EINVAL;
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	fie->code = MEDIA_BUS_FMT_UYVY8_2X8;
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun 	fie->width = supported_modes[fie->index].width;
1754*4882a593Smuzhiyun 	fie->height = supported_modes[fie->index].height;
1755*4882a593Smuzhiyun 	fie->interval = supported_modes[fie->index].max_fps;
1756*4882a593Smuzhiyun 	return 0;
1757*4882a593Smuzhiyun }
1758*4882a593Smuzhiyun 
tc35874x_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)1759*4882a593Smuzhiyun static int tc35874x_get_fmt(struct v4l2_subdev *sd,
1760*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
1761*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1764*4882a593Smuzhiyun 	u8 vi_rep = i2c_rd8(sd, VI_REP);
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	format->format.code = state->mbus_fmt_code;
1767*4882a593Smuzhiyun 	format->format.width = state->timings.bt.width;
1768*4882a593Smuzhiyun 	format->format.height = state->timings.bt.height;
1769*4882a593Smuzhiyun 	format->format.field =
1770*4882a593Smuzhiyun 		state->timings.bt.interlaced ?
1771*4882a593Smuzhiyun 		V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun 	switch (vi_rep & MASK_VOUT_COLOR_SEL) {
1774*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_RGB_FULL:
1775*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_RGB_LIMITED:
1776*4882a593Smuzhiyun 		format->format.colorspace = V4L2_COLORSPACE_SRGB;
1777*4882a593Smuzhiyun 		break;
1778*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_601_YCBCR_LIMITED:
1779*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_601_YCBCR_FULL:
1780*4882a593Smuzhiyun 		format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
1781*4882a593Smuzhiyun 		break;
1782*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_709_YCBCR_FULL:
1783*4882a593Smuzhiyun 	case MASK_VOUT_COLOR_709_YCBCR_LIMITED:
1784*4882a593Smuzhiyun 		format->format.colorspace = V4L2_COLORSPACE_REC709;
1785*4882a593Smuzhiyun 		break;
1786*4882a593Smuzhiyun 	default:
1787*4882a593Smuzhiyun 		format->format.colorspace = 0;
1788*4882a593Smuzhiyun 		break;
1789*4882a593Smuzhiyun 	}
1790*4882a593Smuzhiyun 
1791*4882a593Smuzhiyun 	return 0;
1792*4882a593Smuzhiyun }
1793*4882a593Smuzhiyun 
tc35874x_get_reso_dist(const struct tc35874x_mode * mode,struct v4l2_mbus_framefmt * framefmt)1794*4882a593Smuzhiyun static int tc35874x_get_reso_dist(const struct tc35874x_mode *mode,
1795*4882a593Smuzhiyun 				 struct v4l2_mbus_framefmt *framefmt)
1796*4882a593Smuzhiyun {
1797*4882a593Smuzhiyun 	return abs(mode->width - framefmt->width) +
1798*4882a593Smuzhiyun 	       abs(mode->height - framefmt->height);
1799*4882a593Smuzhiyun }
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun static const struct tc35874x_mode *
tc35874x_find_best_fit(struct v4l2_subdev_format * fmt)1802*4882a593Smuzhiyun tc35874x_find_best_fit(struct v4l2_subdev_format *fmt)
1803*4882a593Smuzhiyun {
1804*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
1805*4882a593Smuzhiyun 	int dist;
1806*4882a593Smuzhiyun 	int cur_best_fit = 0;
1807*4882a593Smuzhiyun 	int cur_best_fit_dist = -1;
1808*4882a593Smuzhiyun 	unsigned int i;
1809*4882a593Smuzhiyun 
1810*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
1811*4882a593Smuzhiyun 		dist = tc35874x_get_reso_dist(&supported_modes[i], framefmt);
1812*4882a593Smuzhiyun 		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
1813*4882a593Smuzhiyun 			cur_best_fit_dist = dist;
1814*4882a593Smuzhiyun 			cur_best_fit = i;
1815*4882a593Smuzhiyun 		}
1816*4882a593Smuzhiyun 	}
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	return &supported_modes[cur_best_fit];
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun 
tc35874x_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)1821*4882a593Smuzhiyun static int tc35874x_set_fmt(struct v4l2_subdev *sd,
1822*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
1823*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
1824*4882a593Smuzhiyun {
1825*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1826*4882a593Smuzhiyun 	const struct tc35874x_mode *mode;
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	u32 code = format->format.code; /* is overwritten by get_fmt */
1829*4882a593Smuzhiyun 	int ret = tc35874x_get_fmt(sd, cfg, format);
1830*4882a593Smuzhiyun 
1831*4882a593Smuzhiyun 	format->format.code = code;
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	if (ret)
1834*4882a593Smuzhiyun 		return ret;
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun 	switch (code) {
1837*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB888_1X24:
1838*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_2X8:
1839*4882a593Smuzhiyun 		break;
1840*4882a593Smuzhiyun 	default:
1841*4882a593Smuzhiyun 		return -EINVAL;
1842*4882a593Smuzhiyun 	}
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
1845*4882a593Smuzhiyun 		return 0;
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 	state->mbus_fmt_code = format->format.code;
1848*4882a593Smuzhiyun 
1849*4882a593Smuzhiyun 	enable_stream(sd, false);
1850*4882a593Smuzhiyun 	mode = tc35874x_find_best_fit(format);
1851*4882a593Smuzhiyun 	state->cur_mode = mode;
1852*4882a593Smuzhiyun 
1853*4882a593Smuzhiyun 	__v4l2_ctrl_s_ctrl(state->link_freq,
1854*4882a593Smuzhiyun 		link_freq_menu_items[0]);
1855*4882a593Smuzhiyun 	__v4l2_ctrl_s_ctrl_int64(state->pixel_rate,
1856*4882a593Smuzhiyun 		TC35874X_PIXEL_RATE_310M);
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 	tc35874x_set_pll(sd);
1859*4882a593Smuzhiyun 	tc35874x_set_csi(sd);
1860*4882a593Smuzhiyun 	tc35874x_set_csi_color_space(sd);
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	return 0;
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun 
tc35874x_g_edid(struct v4l2_subdev * sd,struct v4l2_subdev_edid * edid)1865*4882a593Smuzhiyun static int tc35874x_g_edid(struct v4l2_subdev *sd,
1866*4882a593Smuzhiyun 		struct v4l2_subdev_edid *edid)
1867*4882a593Smuzhiyun {
1868*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	memset(edid->reserved, 0, sizeof(edid->reserved));
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun 	if (edid->pad != 0)
1873*4882a593Smuzhiyun 		return -EINVAL;
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 	if (edid->start_block == 0 && edid->blocks == 0) {
1876*4882a593Smuzhiyun 		edid->blocks = state->edid_blocks_written;
1877*4882a593Smuzhiyun 		return 0;
1878*4882a593Smuzhiyun 	}
1879*4882a593Smuzhiyun 
1880*4882a593Smuzhiyun 	if (state->edid_blocks_written == 0)
1881*4882a593Smuzhiyun 		return -ENODATA;
1882*4882a593Smuzhiyun 
1883*4882a593Smuzhiyun 	if (edid->start_block >= state->edid_blocks_written ||
1884*4882a593Smuzhiyun 			edid->blocks == 0)
1885*4882a593Smuzhiyun 		return -EINVAL;
1886*4882a593Smuzhiyun 
1887*4882a593Smuzhiyun 	if (edid->start_block + edid->blocks > state->edid_blocks_written)
1888*4882a593Smuzhiyun 		edid->blocks = state->edid_blocks_written - edid->start_block;
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun 	i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid,
1891*4882a593Smuzhiyun 			edid->blocks * EDID_BLOCK_SIZE);
1892*4882a593Smuzhiyun 
1893*4882a593Smuzhiyun 	return 0;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun 
tc35874x_s_edid(struct v4l2_subdev * sd,struct v4l2_subdev_edid * edid)1896*4882a593Smuzhiyun static int tc35874x_s_edid(struct v4l2_subdev *sd,
1897*4882a593Smuzhiyun 				struct v4l2_subdev_edid *edid)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1900*4882a593Smuzhiyun 	u16 edid_len = edid->blocks * EDID_BLOCK_SIZE;
1901*4882a593Smuzhiyun 	int i;
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun 	v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
1904*4882a593Smuzhiyun 		 __func__, edid->pad, edid->start_block, edid->blocks);
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 	memset(edid->reserved, 0, sizeof(edid->reserved));
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	if (edid->pad != 0)
1909*4882a593Smuzhiyun 		return -EINVAL;
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun 	if (edid->start_block != 0)
1912*4882a593Smuzhiyun 		return -EINVAL;
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	if (edid->blocks > EDID_NUM_BLOCKS_MAX) {
1915*4882a593Smuzhiyun 		edid->blocks = EDID_NUM_BLOCKS_MAX;
1916*4882a593Smuzhiyun 		return -E2BIG;
1917*4882a593Smuzhiyun 	}
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun 	tc35874x_disable_edid(sd);
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 	i2c_wr8(sd, EDID_LEN1, edid_len & 0xff);
1922*4882a593Smuzhiyun 	i2c_wr8(sd, EDID_LEN2, edid_len >> 8);
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 	if (edid->blocks == 0) {
1925*4882a593Smuzhiyun 		state->edid_blocks_written = 0;
1926*4882a593Smuzhiyun 		return 0;
1927*4882a593Smuzhiyun 	}
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	for (i = 0; i < edid_len; i += EDID_BLOCK_SIZE) {
1930*4882a593Smuzhiyun 		i2c_wr(sd, EDID_RAM + i, edid->edid + i, EDID_BLOCK_SIZE);
1931*4882a593Smuzhiyun 		i2c_wr(sd, EDID_EXT_RAM + i, EDID_extend + i, EDID_BLOCK_SIZE);
1932*4882a593Smuzhiyun 	}
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	state->edid_blocks_written = edid->blocks;
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun 	if (tx_5v_power_present(sd))
1937*4882a593Smuzhiyun 		tc35874x_enable_edid(sd);
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun 	return 0;
1940*4882a593Smuzhiyun }
1941*4882a593Smuzhiyun 
tc35874x_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)1942*4882a593Smuzhiyun static int tc35874x_g_frame_interval(struct v4l2_subdev *sd,
1943*4882a593Smuzhiyun 				    struct v4l2_subdev_frame_interval *fi)
1944*4882a593Smuzhiyun {
1945*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
1946*4882a593Smuzhiyun 	const struct tc35874x_mode *mode = state->cur_mode;
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	mutex_lock(&state->confctl_mutex);
1949*4882a593Smuzhiyun 	fi->interval = mode->max_fps;
1950*4882a593Smuzhiyun 	mutex_unlock(&state->confctl_mutex);
1951*4882a593Smuzhiyun 
1952*4882a593Smuzhiyun 	return 0;
1953*4882a593Smuzhiyun }
1954*4882a593Smuzhiyun 
tc35874x_get_module_inf(struct tc35874x_state * tc35874x,struct rkmodule_inf * inf)1955*4882a593Smuzhiyun static void tc35874x_get_module_inf(struct tc35874x_state *tc35874x,
1956*4882a593Smuzhiyun 				  struct rkmodule_inf *inf)
1957*4882a593Smuzhiyun {
1958*4882a593Smuzhiyun 	memset(inf, 0, sizeof(*inf));
1959*4882a593Smuzhiyun 	strlcpy(inf->base.sensor, TC35874X_NAME, sizeof(inf->base.sensor));
1960*4882a593Smuzhiyun 	strlcpy(inf->base.module, tc35874x->module_name,
1961*4882a593Smuzhiyun 		sizeof(inf->base.module));
1962*4882a593Smuzhiyun 	strlcpy(inf->base.lens, tc35874x->len_name, sizeof(inf->base.lens));
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun 
tc35874x_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)1965*4882a593Smuzhiyun static long tc35874x_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1966*4882a593Smuzhiyun {
1967*4882a593Smuzhiyun 	struct tc35874x_state *tc35874x = to_state(sd);
1968*4882a593Smuzhiyun 	long ret = 0;
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	switch (cmd) {
1971*4882a593Smuzhiyun 	case RKMODULE_GET_MODULE_INFO:
1972*4882a593Smuzhiyun 		tc35874x_get_module_inf(tc35874x, (struct rkmodule_inf *)arg);
1973*4882a593Smuzhiyun 		break;
1974*4882a593Smuzhiyun 	default:
1975*4882a593Smuzhiyun 		ret = -ENOIOCTLCMD;
1976*4882a593Smuzhiyun 		break;
1977*4882a593Smuzhiyun 	}
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 	return ret;
1980*4882a593Smuzhiyun }
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
tc35874x_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)1983*4882a593Smuzhiyun static long tc35874x_compat_ioctl32(struct v4l2_subdev *sd,
1984*4882a593Smuzhiyun 				  unsigned int cmd, unsigned long arg)
1985*4882a593Smuzhiyun {
1986*4882a593Smuzhiyun 	void __user *up = compat_ptr(arg);
1987*4882a593Smuzhiyun 	struct rkmodule_inf *inf;
1988*4882a593Smuzhiyun 	struct rkmodule_awb_cfg *cfg;
1989*4882a593Smuzhiyun 	long ret;
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	switch (cmd) {
1992*4882a593Smuzhiyun 	case RKMODULE_GET_MODULE_INFO:
1993*4882a593Smuzhiyun 		inf = kzalloc(sizeof(*inf), GFP_KERNEL);
1994*4882a593Smuzhiyun 		if (!inf) {
1995*4882a593Smuzhiyun 			ret = -ENOMEM;
1996*4882a593Smuzhiyun 			return ret;
1997*4882a593Smuzhiyun 		}
1998*4882a593Smuzhiyun 
1999*4882a593Smuzhiyun 		ret = tc35874x_ioctl(sd, cmd, inf);
2000*4882a593Smuzhiyun 		if (!ret) {
2001*4882a593Smuzhiyun 			ret = copy_to_user(up, inf, sizeof(*inf));
2002*4882a593Smuzhiyun 			if (ret)
2003*4882a593Smuzhiyun 				ret = -EFAULT;
2004*4882a593Smuzhiyun 		}
2005*4882a593Smuzhiyun 		kfree(inf);
2006*4882a593Smuzhiyun 		break;
2007*4882a593Smuzhiyun 	case RKMODULE_AWB_CFG:
2008*4882a593Smuzhiyun 		cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
2009*4882a593Smuzhiyun 		if (!cfg) {
2010*4882a593Smuzhiyun 			ret = -ENOMEM;
2011*4882a593Smuzhiyun 			return ret;
2012*4882a593Smuzhiyun 		}
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 		ret = copy_from_user(cfg, up, sizeof(*cfg));
2015*4882a593Smuzhiyun 		if (!ret)
2016*4882a593Smuzhiyun 			ret = tc35874x_ioctl(sd, cmd, cfg);
2017*4882a593Smuzhiyun 		else
2018*4882a593Smuzhiyun 			ret = -EFAULT;
2019*4882a593Smuzhiyun 		kfree(cfg);
2020*4882a593Smuzhiyun 		break;
2021*4882a593Smuzhiyun 	default:
2022*4882a593Smuzhiyun 		ret = -ENOIOCTLCMD;
2023*4882a593Smuzhiyun 		break;
2024*4882a593Smuzhiyun 	}
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	return ret;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun #endif
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun /* -------------------------------------------------------------------------- */
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun static const struct v4l2_ctrl_ops tc35874x_ctrl_ops = {
2033*4882a593Smuzhiyun 	.g_volatile_ctrl = tc35874x_get_ctrl,
2034*4882a593Smuzhiyun };
2035*4882a593Smuzhiyun 
2036*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops tc35874x_core_ops = {
2037*4882a593Smuzhiyun 	.log_status = tc35874x_log_status,
2038*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
2039*4882a593Smuzhiyun 	.g_register = tc35874x_g_register,
2040*4882a593Smuzhiyun 	.s_register = tc35874x_s_register,
2041*4882a593Smuzhiyun #endif
2042*4882a593Smuzhiyun 	.interrupt_service_routine = tc35874x_isr,
2043*4882a593Smuzhiyun 	.subscribe_event = tc35874x_subscribe_event,
2044*4882a593Smuzhiyun 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
2045*4882a593Smuzhiyun 	.ioctl = tc35874x_ioctl,
2046*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
2047*4882a593Smuzhiyun 	.compat_ioctl32 = tc35874x_compat_ioctl32,
2048*4882a593Smuzhiyun #endif
2049*4882a593Smuzhiyun };
2050*4882a593Smuzhiyun 
2051*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops tc35874x_video_ops = {
2052*4882a593Smuzhiyun 	.g_input_status = tc35874x_g_input_status,
2053*4882a593Smuzhiyun 	.s_dv_timings = tc35874x_s_dv_timings,
2054*4882a593Smuzhiyun 	.g_dv_timings = tc35874x_g_dv_timings,
2055*4882a593Smuzhiyun 	.query_dv_timings = tc35874x_query_dv_timings,
2056*4882a593Smuzhiyun 	.s_stream = tc35874x_s_stream,
2057*4882a593Smuzhiyun 	.g_frame_interval = tc35874x_g_frame_interval,
2058*4882a593Smuzhiyun };
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops tc35874x_pad_ops = {
2061*4882a593Smuzhiyun 	.enum_mbus_code = tc35874x_enum_mbus_code,
2062*4882a593Smuzhiyun 	.enum_frame_size = tc35874x_enum_frame_sizes,
2063*4882a593Smuzhiyun 	.enum_frame_interval = tc35874x_enum_frame_interval,
2064*4882a593Smuzhiyun 	.set_fmt = tc35874x_set_fmt,
2065*4882a593Smuzhiyun 	.get_fmt = tc35874x_get_fmt,
2066*4882a593Smuzhiyun 	.get_edid = tc35874x_g_edid,
2067*4882a593Smuzhiyun 	.set_edid = tc35874x_s_edid,
2068*4882a593Smuzhiyun 	.enum_dv_timings = tc35874x_enum_dv_timings,
2069*4882a593Smuzhiyun 	.dv_timings_cap = tc35874x_dv_timings_cap,
2070*4882a593Smuzhiyun 	.get_mbus_config = tc35874x_g_mbus_config,
2071*4882a593Smuzhiyun };
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun static const struct v4l2_subdev_ops tc35874x_ops = {
2074*4882a593Smuzhiyun 	.core = &tc35874x_core_ops,
2075*4882a593Smuzhiyun 	.video = &tc35874x_video_ops,
2076*4882a593Smuzhiyun 	.pad = &tc35874x_pad_ops,
2077*4882a593Smuzhiyun };
2078*4882a593Smuzhiyun 
2079*4882a593Smuzhiyun /* --------------- CUSTOM CTRLS --------------- */
tc35874x_get_custom_ctrl(struct v4l2_ctrl * ctrl)2080*4882a593Smuzhiyun static int tc35874x_get_custom_ctrl(struct v4l2_ctrl *ctrl)
2081*4882a593Smuzhiyun {
2082*4882a593Smuzhiyun 	int ret = -EINVAL;
2083*4882a593Smuzhiyun 	struct tc35874x_state *state = container_of(ctrl->handler,
2084*4882a593Smuzhiyun 			struct tc35874x_state, hdl);
2085*4882a593Smuzhiyun 	struct v4l2_subdev *sd = &state->sd;
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 	if (ctrl->id == TC35874X_CID_AUDIO_SAMPLING_RATE) {
2088*4882a593Smuzhiyun 		ret = get_audio_sampling_rate(sd);
2089*4882a593Smuzhiyun 		*ctrl->p_new.p_s32 = ret;
2090*4882a593Smuzhiyun 	}
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	return ret;
2093*4882a593Smuzhiyun }
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun static const struct v4l2_ctrl_ops tc35874x_custom_ctrl_ops = {
2096*4882a593Smuzhiyun 	.g_volatile_ctrl = tc35874x_get_custom_ctrl,
2097*4882a593Smuzhiyun };
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun static const struct v4l2_ctrl_config tc35874x_ctrl_audio_sampling_rate = {
2100*4882a593Smuzhiyun 	.ops = &tc35874x_custom_ctrl_ops,
2101*4882a593Smuzhiyun 	.id = TC35874X_CID_AUDIO_SAMPLING_RATE,
2102*4882a593Smuzhiyun 	.name = "Audio sampling rate",
2103*4882a593Smuzhiyun 	.type = V4L2_CTRL_TYPE_INTEGER,
2104*4882a593Smuzhiyun 	.min = 0,
2105*4882a593Smuzhiyun 	.max = 768000,
2106*4882a593Smuzhiyun 	.step = 1,
2107*4882a593Smuzhiyun 	.def = 0,
2108*4882a593Smuzhiyun 	.flags = V4L2_CTRL_FLAG_READ_ONLY,
2109*4882a593Smuzhiyun };
2110*4882a593Smuzhiyun 
2111*4882a593Smuzhiyun static const struct v4l2_ctrl_config tc35874x_ctrl_audio_present = {
2112*4882a593Smuzhiyun 	.id = TC35874X_CID_AUDIO_PRESENT,
2113*4882a593Smuzhiyun 	.name = "Audio present",
2114*4882a593Smuzhiyun 	.type = V4L2_CTRL_TYPE_BOOLEAN,
2115*4882a593Smuzhiyun 	.min = 0,
2116*4882a593Smuzhiyun 	.max = 1,
2117*4882a593Smuzhiyun 	.step = 1,
2118*4882a593Smuzhiyun 	.def = 0,
2119*4882a593Smuzhiyun 	.flags = V4L2_CTRL_FLAG_READ_ONLY,
2120*4882a593Smuzhiyun };
2121*4882a593Smuzhiyun 
2122*4882a593Smuzhiyun /* --------------- PROBE / REMOVE --------------- */
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun #ifdef CONFIG_OF
tc35874x_gpio_reset(struct tc35874x_state * state)2125*4882a593Smuzhiyun static void tc35874x_gpio_reset(struct tc35874x_state *state)
2126*4882a593Smuzhiyun {
2127*4882a593Smuzhiyun 	usleep_range(5000, 10000);
2128*4882a593Smuzhiyun 	gpiod_set_value(state->reset_gpio, 1);
2129*4882a593Smuzhiyun 	usleep_range(1000, 2000);
2130*4882a593Smuzhiyun 	gpiod_set_value(state->reset_gpio, 0);
2131*4882a593Smuzhiyun 	msleep(20);
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun 
tc35874x_probe_of(struct tc35874x_state * state)2134*4882a593Smuzhiyun static int tc35874x_probe_of(struct tc35874x_state *state)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun 	struct device *dev = &state->i2c_client->dev;
2137*4882a593Smuzhiyun 	struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
2138*4882a593Smuzhiyun 	struct device_node *ep;
2139*4882a593Smuzhiyun 	struct clk *refclk;
2140*4882a593Smuzhiyun 	u32 bps_pr_lane;
2141*4882a593Smuzhiyun 	int ret = -EINVAL;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	refclk = devm_clk_get(dev, "refclk");
2144*4882a593Smuzhiyun 	if (IS_ERR(refclk)) {
2145*4882a593Smuzhiyun 		if (PTR_ERR(refclk) != -EPROBE_DEFER)
2146*4882a593Smuzhiyun 			dev_err(dev, "failed to get refclk: %ld\n",
2147*4882a593Smuzhiyun 				PTR_ERR(refclk));
2148*4882a593Smuzhiyun 		return PTR_ERR(refclk);
2149*4882a593Smuzhiyun 	}
2150*4882a593Smuzhiyun 
2151*4882a593Smuzhiyun 	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
2152*4882a593Smuzhiyun 	if (!ep) {
2153*4882a593Smuzhiyun 		dev_err(dev, "missing endpoint node\n");
2154*4882a593Smuzhiyun 		return -EINVAL;
2155*4882a593Smuzhiyun 	}
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
2158*4882a593Smuzhiyun 	if (ret) {
2159*4882a593Smuzhiyun 		dev_err(dev, "failed to parse endpoint\n");
2160*4882a593Smuzhiyun 		goto put_node;
2161*4882a593Smuzhiyun 	}
2162*4882a593Smuzhiyun 
2163*4882a593Smuzhiyun 	if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY ||
2164*4882a593Smuzhiyun 	    endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
2165*4882a593Smuzhiyun 	    endpoint.nr_of_link_frequencies == 0) {
2166*4882a593Smuzhiyun 		dev_err(dev, "missing CSI-2 properties in endpoint\n");
2167*4882a593Smuzhiyun 		goto free_endpoint;
2168*4882a593Smuzhiyun 	}
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun 	state->csi_lanes_in_use = endpoint.bus.mipi_csi2.num_data_lanes;
2171*4882a593Smuzhiyun 	state->bus = endpoint.bus.mipi_csi2;
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun 	ret = clk_prepare_enable(refclk);
2174*4882a593Smuzhiyun 	if (ret) {
2175*4882a593Smuzhiyun 		dev_err(dev, "Failed! to enable clock\n");
2176*4882a593Smuzhiyun 		goto free_endpoint;
2177*4882a593Smuzhiyun 	}
2178*4882a593Smuzhiyun 
2179*4882a593Smuzhiyun 	state->pdata.refclk_hz = clk_get_rate(refclk);
2180*4882a593Smuzhiyun 	state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
2181*4882a593Smuzhiyun 	state->pdata.enable_hdcp = false;
2182*4882a593Smuzhiyun 	/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
2183*4882a593Smuzhiyun 	state->pdata.fifo_level = 16;
2184*4882a593Smuzhiyun 	/*
2185*4882a593Smuzhiyun 	 * The PLL input clock is obtained by dividing refclk by pll_prd.
2186*4882a593Smuzhiyun 	 * It must be between 6 MHz and 40 MHz, lower frequency is better.
2187*4882a593Smuzhiyun 	 */
2188*4882a593Smuzhiyun 	switch (state->pdata.refclk_hz) {
2189*4882a593Smuzhiyun 	case 26000000:
2190*4882a593Smuzhiyun 	case 27000000:
2191*4882a593Smuzhiyun 	case 42000000:
2192*4882a593Smuzhiyun 		state->pdata.pll_prd = state->pdata.refclk_hz / 6000000;
2193*4882a593Smuzhiyun 		break;
2194*4882a593Smuzhiyun 	default:
2195*4882a593Smuzhiyun 		dev_err(dev, "unsupported refclk rate: %u Hz\n",
2196*4882a593Smuzhiyun 			state->pdata.refclk_hz);
2197*4882a593Smuzhiyun 		goto disable_clk;
2198*4882a593Smuzhiyun 	}
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun 	/*
2201*4882a593Smuzhiyun 	 * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
2202*4882a593Smuzhiyun 	 * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
2203*4882a593Smuzhiyun 	 */
2204*4882a593Smuzhiyun 	bps_pr_lane = 2 * endpoint.link_frequencies[0];
2205*4882a593Smuzhiyun 	if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
2206*4882a593Smuzhiyun 		dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
2207*4882a593Smuzhiyun 		goto disable_clk;
2208*4882a593Smuzhiyun 	}
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun 	/* The CSI speed per lane is refclk / pll_prd * pll_fbd */
2211*4882a593Smuzhiyun 	state->pdata.pll_fbd = bps_pr_lane /
2212*4882a593Smuzhiyun 			       state->pdata.refclk_hz * state->pdata.pll_prd;
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun 	/*
2215*4882a593Smuzhiyun 	 * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz
2216*4882a593Smuzhiyun 	 * link frequency). In principle it should be possible to calculate
2217*4882a593Smuzhiyun 	 * them based on link frequency and resolution.
2218*4882a593Smuzhiyun 	 */
2219*4882a593Smuzhiyun 	if (bps_pr_lane != 594000000U)
2220*4882a593Smuzhiyun 		dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane);
2221*4882a593Smuzhiyun 	state->pdata.lineinitcnt = 0xe80;
2222*4882a593Smuzhiyun 	state->pdata.lptxtimecnt = 0x003;
2223*4882a593Smuzhiyun 	/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
2224*4882a593Smuzhiyun 	state->pdata.tclk_headercnt = 0x1403;
2225*4882a593Smuzhiyun 	state->pdata.tclk_trailcnt = 0x00;
2226*4882a593Smuzhiyun 	/* ths-preparecnt: 3, ths-zerocnt: 1 */
2227*4882a593Smuzhiyun 	state->pdata.ths_headercnt = 0x0103;
2228*4882a593Smuzhiyun 	state->pdata.twakeup = 0x4882;
2229*4882a593Smuzhiyun 	state->pdata.tclk_postcnt = 0x008;
2230*4882a593Smuzhiyun 	state->pdata.ths_trailcnt = 0x2;
2231*4882a593Smuzhiyun 	state->pdata.hstxvregcnt = 0;
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 	state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
2234*4882a593Smuzhiyun 						    GPIOD_OUT_LOW);
2235*4882a593Smuzhiyun 	if (IS_ERR(state->reset_gpio)) {
2236*4882a593Smuzhiyun 		dev_err(dev, "failed to get reset gpio\n");
2237*4882a593Smuzhiyun 		ret = PTR_ERR(state->reset_gpio);
2238*4882a593Smuzhiyun 		goto disable_clk;
2239*4882a593Smuzhiyun 	}
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 	if (state->reset_gpio)
2242*4882a593Smuzhiyun 		tc35874x_gpio_reset(state);
2243*4882a593Smuzhiyun 
2244*4882a593Smuzhiyun 	ret = 0;
2245*4882a593Smuzhiyun 	goto free_endpoint;
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun disable_clk:
2248*4882a593Smuzhiyun 	clk_disable_unprepare(refclk);
2249*4882a593Smuzhiyun free_endpoint:
2250*4882a593Smuzhiyun 	v4l2_fwnode_endpoint_free(&endpoint);
2251*4882a593Smuzhiyun put_node:
2252*4882a593Smuzhiyun 	of_node_put(ep);
2253*4882a593Smuzhiyun 	return ret;
2254*4882a593Smuzhiyun }
2255*4882a593Smuzhiyun #else
tc35874x_probe_of(struct tc35874x_state * state)2256*4882a593Smuzhiyun static inline int tc35874x_probe_of(struct tc35874x_state *state)
2257*4882a593Smuzhiyun {
2258*4882a593Smuzhiyun 	return -ENODEV;
2259*4882a593Smuzhiyun }
2260*4882a593Smuzhiyun #endif
2261*4882a593Smuzhiyun 
tc35874x_probe(struct i2c_client * client,const struct i2c_device_id * id)2262*4882a593Smuzhiyun static int tc35874x_probe(struct i2c_client *client,
2263*4882a593Smuzhiyun 			  const struct i2c_device_id *id)
2264*4882a593Smuzhiyun {
2265*4882a593Smuzhiyun 	static struct v4l2_dv_timings default_timing =
2266*4882a593Smuzhiyun 		V4L2_DV_BT_CEA_640X480P59_94;
2267*4882a593Smuzhiyun 	struct tc35874x_state *state;
2268*4882a593Smuzhiyun 	struct tc35874x_platform_data *pdata = client->dev.platform_data;
2269*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
2270*4882a593Smuzhiyun 	struct v4l2_subdev_edid def_edid;
2271*4882a593Smuzhiyun 	struct device *dev = &client->dev;
2272*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
2273*4882a593Smuzhiyun 	char facing[2];
2274*4882a593Smuzhiyun 	int err, data;
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun 	dev_info(dev, "driver version: %02x.%02x.%02x",
2277*4882a593Smuzhiyun 		DRIVER_VERSION >> 16,
2278*4882a593Smuzhiyun 		(DRIVER_VERSION & 0xff00) >> 8,
2279*4882a593Smuzhiyun 		DRIVER_VERSION & 0x00ff);
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
2282*4882a593Smuzhiyun 		return -EIO;
2283*4882a593Smuzhiyun 	v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n",
2284*4882a593Smuzhiyun 		client->addr << 1, client->adapter->name);
2285*4882a593Smuzhiyun 
2286*4882a593Smuzhiyun 	state = devm_kzalloc(&client->dev, sizeof(struct tc35874x_state),
2287*4882a593Smuzhiyun 			GFP_KERNEL);
2288*4882a593Smuzhiyun 	if (!state)
2289*4882a593Smuzhiyun 		return -ENOMEM;
2290*4882a593Smuzhiyun 
2291*4882a593Smuzhiyun 	err = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
2292*4882a593Smuzhiyun 				   &state->module_index);
2293*4882a593Smuzhiyun 	err |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
2294*4882a593Smuzhiyun 				       &state->module_facing);
2295*4882a593Smuzhiyun 	err |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
2296*4882a593Smuzhiyun 				       &state->module_name);
2297*4882a593Smuzhiyun 	err |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
2298*4882a593Smuzhiyun 				       &state->len_name);
2299*4882a593Smuzhiyun 	if (err) {
2300*4882a593Smuzhiyun 		dev_err(dev, "could not get module information!\n");
2301*4882a593Smuzhiyun 		return -EINVAL;
2302*4882a593Smuzhiyun 	}
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun 	state->i2c_client = client;
2305*4882a593Smuzhiyun 	state->cur_mode = &supported_modes[0];
2306*4882a593Smuzhiyun 
2307*4882a593Smuzhiyun 	/* platform data */
2308*4882a593Smuzhiyun 	if (pdata) {
2309*4882a593Smuzhiyun 		state->pdata = *pdata;
2310*4882a593Smuzhiyun 		state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
2311*4882a593Smuzhiyun 	} else {
2312*4882a593Smuzhiyun 		err = tc35874x_probe_of(state);
2313*4882a593Smuzhiyun 		if (err == -ENODEV)
2314*4882a593Smuzhiyun 			v4l_err(client, "No platform data!\n");
2315*4882a593Smuzhiyun 		if (err)
2316*4882a593Smuzhiyun 			return err;
2317*4882a593Smuzhiyun 	}
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 	sd = &state->sd;
2320*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &tc35874x_ops);
2321*4882a593Smuzhiyun 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
2322*4882a593Smuzhiyun 
2323*4882a593Smuzhiyun 	/* i2c access */
2324*4882a593Smuzhiyun 	data = i2c_rd16(sd, CHIPID) & MASK_CHIPID;
2325*4882a593Smuzhiyun 	switch (data) {
2326*4882a593Smuzhiyun 	case 0x0000:
2327*4882a593Smuzhiyun 	case 0x4700:
2328*4882a593Smuzhiyun 		break;
2329*4882a593Smuzhiyun 	default:
2330*4882a593Smuzhiyun 		v4l2_info(sd, "not a tc35874x on address 0x%x\n",
2331*4882a593Smuzhiyun 			  client->addr << 1);
2332*4882a593Smuzhiyun 		return -ENODEV;
2333*4882a593Smuzhiyun 	}
2334*4882a593Smuzhiyun 
2335*4882a593Smuzhiyun 	/* control handlers */
2336*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(&state->hdl, 4);
2337*4882a593Smuzhiyun 
2338*4882a593Smuzhiyun 	state->link_freq = v4l2_ctrl_new_int_menu(&state->hdl, NULL,
2339*4882a593Smuzhiyun 		V4L2_CID_LINK_FREQ, 0, 0, link_freq_menu_items);
2340*4882a593Smuzhiyun 
2341*4882a593Smuzhiyun 	state->pixel_rate = v4l2_ctrl_new_std(&state->hdl, NULL,
2342*4882a593Smuzhiyun 		V4L2_CID_PIXEL_RATE, 0, TC35874X_PIXEL_RATE_310M, 1,
2343*4882a593Smuzhiyun 		TC35874X_PIXEL_RATE_310M);
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun 	state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl,
2346*4882a593Smuzhiyun 			&tc35874x_ctrl_ops, V4L2_CID_DV_RX_POWER_PRESENT,
2347*4882a593Smuzhiyun 			0, 1, 0, 0);
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 	if (state->detect_tx_5v_ctrl)
2350*4882a593Smuzhiyun 		state->detect_tx_5v_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
2351*4882a593Smuzhiyun 
2352*4882a593Smuzhiyun 	/* custom controls */
2353*4882a593Smuzhiyun 	state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl,
2354*4882a593Smuzhiyun 			&tc35874x_ctrl_audio_sampling_rate, NULL);
2355*4882a593Smuzhiyun 	if (state->audio_sampling_rate_ctrl)
2356*4882a593Smuzhiyun 		state->audio_sampling_rate_ctrl->flags |=
2357*4882a593Smuzhiyun 			V4L2_CTRL_FLAG_VOLATILE;
2358*4882a593Smuzhiyun 
2359*4882a593Smuzhiyun 	state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl,
2360*4882a593Smuzhiyun 			&tc35874x_ctrl_audio_present, NULL);
2361*4882a593Smuzhiyun 
2362*4882a593Smuzhiyun 	sd->ctrl_handler = &state->hdl;
2363*4882a593Smuzhiyun 	if (state->hdl.error) {
2364*4882a593Smuzhiyun 		err = state->hdl.error;
2365*4882a593Smuzhiyun 		goto err_hdl;
2366*4882a593Smuzhiyun 	}
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 	if (tc35874x_update_controls(sd)) {
2369*4882a593Smuzhiyun 		err = -ENODEV;
2370*4882a593Smuzhiyun 		goto err_hdl;
2371*4882a593Smuzhiyun 	}
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun 	state->pad.flags = MEDIA_PAD_FL_SOURCE;
2374*4882a593Smuzhiyun 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
2375*4882a593Smuzhiyun 	err = media_entity_pads_init(&sd->entity, 1, &state->pad);
2376*4882a593Smuzhiyun 	if (err < 0)
2377*4882a593Smuzhiyun 		goto err_hdl;
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	state->mbus_fmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
2380*4882a593Smuzhiyun 
2381*4882a593Smuzhiyun 	sd->dev = &client->dev;
2382*4882a593Smuzhiyun 	memset(facing, 0, sizeof(facing));
2383*4882a593Smuzhiyun 	if (strcmp(state->module_facing, "back") == 0)
2384*4882a593Smuzhiyun 		facing[0] = 'b';
2385*4882a593Smuzhiyun 	else
2386*4882a593Smuzhiyun 		facing[0] = 'f';
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 	snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
2389*4882a593Smuzhiyun 		 state->module_index, facing,
2390*4882a593Smuzhiyun 		 TC35874X_NAME, dev_name(sd->dev));
2391*4882a593Smuzhiyun 	err = v4l2_async_register_subdev(sd);
2392*4882a593Smuzhiyun 	if (err < 0)
2393*4882a593Smuzhiyun 		goto err_hdl;
2394*4882a593Smuzhiyun 
2395*4882a593Smuzhiyun 	mutex_init(&state->confctl_mutex);
2396*4882a593Smuzhiyun 
2397*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
2398*4882a593Smuzhiyun 			tc35874x_delayed_work_enable_hotplug);
2399*4882a593Smuzhiyun 
2400*4882a593Smuzhiyun 	tc35874x_initial_setup(sd);
2401*4882a593Smuzhiyun 
2402*4882a593Smuzhiyun 	tc35874x_s_dv_timings(sd, &default_timing);
2403*4882a593Smuzhiyun 
2404*4882a593Smuzhiyun 	tc35874x_set_csi_color_space(sd);
2405*4882a593Smuzhiyun 
2406*4882a593Smuzhiyun 	def_edid.pad = 0;
2407*4882a593Smuzhiyun 	def_edid.start_block = 0;
2408*4882a593Smuzhiyun 	def_edid.blocks = 1;
2409*4882a593Smuzhiyun 	def_edid.edid = EDID_1920x1080_60;
2410*4882a593Smuzhiyun 
2411*4882a593Smuzhiyun 	tc35874x_s_edid(sd, &def_edid);
2412*4882a593Smuzhiyun 
2413*4882a593Smuzhiyun 	tc35874x_init_interrupts(sd);
2414*4882a593Smuzhiyun 
2415*4882a593Smuzhiyun 	if (state->i2c_client->irq) {
2416*4882a593Smuzhiyun 		err = devm_request_threaded_irq(&client->dev,
2417*4882a593Smuzhiyun 						state->i2c_client->irq,
2418*4882a593Smuzhiyun 						NULL, tc35874x_irq_handler,
2419*4882a593Smuzhiyun 						IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
2420*4882a593Smuzhiyun 						"tc35874x", state);
2421*4882a593Smuzhiyun 		if (err)
2422*4882a593Smuzhiyun 			goto err_work_queues;
2423*4882a593Smuzhiyun 	} else {
2424*4882a593Smuzhiyun 		INIT_WORK(&state->work_i2c_poll,
2425*4882a593Smuzhiyun 			  tc35874x_work_i2c_poll);
2426*4882a593Smuzhiyun 		timer_setup(&state->timer, tc35874x_irq_poll_timer, 0);
2427*4882a593Smuzhiyun 		state->timer.expires = jiffies +
2428*4882a593Smuzhiyun 				       msecs_to_jiffies(POLL_INTERVAL_MS);
2429*4882a593Smuzhiyun 		add_timer(&state->timer);
2430*4882a593Smuzhiyun 	}
2431*4882a593Smuzhiyun 
2432*4882a593Smuzhiyun 	tc35874x_enable_interrupts(sd, tx_5v_power_present(sd));
2433*4882a593Smuzhiyun 	i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff);
2434*4882a593Smuzhiyun 
2435*4882a593Smuzhiyun 	err = v4l2_ctrl_handler_setup(sd->ctrl_handler);
2436*4882a593Smuzhiyun 	if (err)
2437*4882a593Smuzhiyun 		goto err_work_queues;
2438*4882a593Smuzhiyun 
2439*4882a593Smuzhiyun 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
2440*4882a593Smuzhiyun 		  client->addr << 1, client->adapter->name);
2441*4882a593Smuzhiyun 
2442*4882a593Smuzhiyun 	return 0;
2443*4882a593Smuzhiyun 
2444*4882a593Smuzhiyun err_work_queues:
2445*4882a593Smuzhiyun 	if (!state->i2c_client->irq)
2446*4882a593Smuzhiyun 		flush_work(&state->work_i2c_poll);
2447*4882a593Smuzhiyun 	cancel_delayed_work(&state->delayed_work_enable_hotplug);
2448*4882a593Smuzhiyun 	mutex_destroy(&state->confctl_mutex);
2449*4882a593Smuzhiyun err_hdl:
2450*4882a593Smuzhiyun 	media_entity_cleanup(&sd->entity);
2451*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&state->hdl);
2452*4882a593Smuzhiyun 	return err;
2453*4882a593Smuzhiyun }
2454*4882a593Smuzhiyun 
tc35874x_remove(struct i2c_client * client)2455*4882a593Smuzhiyun static int tc35874x_remove(struct i2c_client *client)
2456*4882a593Smuzhiyun {
2457*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
2458*4882a593Smuzhiyun 	struct tc35874x_state *state = to_state(sd);
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 	if (!state->i2c_client->irq) {
2461*4882a593Smuzhiyun 		del_timer_sync(&state->timer);
2462*4882a593Smuzhiyun 		flush_work(&state->work_i2c_poll);
2463*4882a593Smuzhiyun 	}
2464*4882a593Smuzhiyun 	cancel_delayed_work(&state->delayed_work_enable_hotplug);
2465*4882a593Smuzhiyun 	v4l2_async_unregister_subdev(sd);
2466*4882a593Smuzhiyun 	v4l2_device_unregister_subdev(sd);
2467*4882a593Smuzhiyun 	mutex_destroy(&state->confctl_mutex);
2468*4882a593Smuzhiyun 	media_entity_cleanup(&sd->entity);
2469*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&state->hdl);
2470*4882a593Smuzhiyun 
2471*4882a593Smuzhiyun 	return 0;
2472*4882a593Smuzhiyun }
2473*4882a593Smuzhiyun 
2474*4882a593Smuzhiyun static struct i2c_device_id tc35874x_id[] = {
2475*4882a593Smuzhiyun 	{"tc358743", 0},
2476*4882a593Smuzhiyun 	{"tc358749", 0},
2477*4882a593Smuzhiyun 	{}
2478*4882a593Smuzhiyun };
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, tc35874x_id);
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF)
2483*4882a593Smuzhiyun static const struct of_device_id tc35874x_of_match[] = {
2484*4882a593Smuzhiyun 	{ .compatible = "toshiba,tc358743" },
2485*4882a593Smuzhiyun 	{ .compatible = "toshiba,tc358749" },
2486*4882a593Smuzhiyun 	{},
2487*4882a593Smuzhiyun };
2488*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, tc35874x_of_match);
2489*4882a593Smuzhiyun #endif
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun static struct i2c_driver tc35874x_driver = {
2492*4882a593Smuzhiyun 	.driver = {
2493*4882a593Smuzhiyun 		.name = TC35874X_NAME,
2494*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(tc35874x_of_match),
2495*4882a593Smuzhiyun 	},
2496*4882a593Smuzhiyun 	.probe = tc35874x_probe,
2497*4882a593Smuzhiyun 	.remove = tc35874x_remove,
2498*4882a593Smuzhiyun 	.id_table = tc35874x_id,
2499*4882a593Smuzhiyun };
2500*4882a593Smuzhiyun 
tc35874x_driver_init(void)2501*4882a593Smuzhiyun static int __init tc35874x_driver_init(void)
2502*4882a593Smuzhiyun {
2503*4882a593Smuzhiyun 	return i2c_add_driver(&tc35874x_driver);
2504*4882a593Smuzhiyun }
2505*4882a593Smuzhiyun 
tc35874x_driver_exit(void)2506*4882a593Smuzhiyun static void __exit tc35874x_driver_exit(void)
2507*4882a593Smuzhiyun {
2508*4882a593Smuzhiyun 	i2c_del_driver(&tc35874x_driver);
2509*4882a593Smuzhiyun }
2510*4882a593Smuzhiyun 
2511*4882a593Smuzhiyun device_initcall_sync(tc35874x_driver_init);
2512*4882a593Smuzhiyun module_exit(tc35874x_driver_exit);
2513