xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/it6616.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * it6616 HDMI to MIPI CSI-2 bridge driver.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Jau-Chih.Tseng@ite.com.tw
8*4882a593Smuzhiyun  *	   Jianwei Fan <jianwei.fan@rock-chips.com>
9*4882a593Smuzhiyun  * V0.0X01.0X00 first version.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun // #define DEBUG
13*4882a593Smuzhiyun #include <linux/clk.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
16*4882a593Smuzhiyun #include <linux/hdmi.h>
17*4882a593Smuzhiyun #include <linux/i2c.h>
18*4882a593Smuzhiyun #include <linux/interrupt.h>
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/of_graph.h>
22*4882a593Smuzhiyun #include <linux/rk-camera-module.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/timer.h>
25*4882a593Smuzhiyun #include <linux/v4l2-dv-timings.h>
26*4882a593Smuzhiyun #include <linux/version.h>
27*4882a593Smuzhiyun #include <linux/videodev2.h>
28*4882a593Smuzhiyun #include <linux/workqueue.h>
29*4882a593Smuzhiyun #include <linux/compat.h>
30*4882a593Smuzhiyun #include <linux/regmap.h>
31*4882a593Smuzhiyun #include <media/v4l2-controls_rockchip.h>
32*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
33*4882a593Smuzhiyun #include <media/v4l2-device.h>
34*4882a593Smuzhiyun #include <media/v4l2-dv-timings.h>
35*4882a593Smuzhiyun #include <media/v4l2-event.h>
36*4882a593Smuzhiyun #include <media/v4l2-fwnode.h>
37*4882a593Smuzhiyun #include <media/cec.h>
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x00)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static int debug;
42*4882a593Smuzhiyun module_param(debug, int, 0644);
43*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "debug level (0-3)");
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define IT6616_NAME		"IT6616"
46*4882a593Smuzhiyun #define POLL_INTERVAL_MS	100
47*4882a593Smuzhiyun #define TIMER_100MS		105
48*4882a593Smuzhiyun #define IT6616_XVCLK_FREQ	27000000
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define IT6616_LINK_FREQ	400000000
51*4882a593Smuzhiyun #define IT6616_PIXEL_RATE	400000000
52*4882a593Smuzhiyun #define IT6616_MEDIA_BUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define I2C_ADR_HDMI            0x90
55*4882a593Smuzhiyun #define I2C_ADR_MIPI            0xAC
56*4882a593Smuzhiyun #define I2C_ADR_EDID            0xA8
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun //define in HDMI SPEC 2.0 PAGE 84
59*4882a593Smuzhiyun #define AUDIO_SAMPLING_1024K    0x35
60*4882a593Smuzhiyun #define AUDIO_SAMPLING_768K     0x09
61*4882a593Smuzhiyun #define AUDIO_SAMPLING_512K     0x3B
62*4882a593Smuzhiyun #define AUDIO_SAMPLING_384K     0x05
63*4882a593Smuzhiyun #define AUDIO_SAMPLING_256K     0x1B
64*4882a593Smuzhiyun #define AUDIO_SAMPLING_192K     0x0E
65*4882a593Smuzhiyun #define AUDIO_SAMPLING_176P4K   0x0C
66*4882a593Smuzhiyun #define AUDIO_SAMPLING_128K     0x2B
67*4882a593Smuzhiyun #define AUDIO_SAMPLING_96K      0x0A
68*4882a593Smuzhiyun #define AUDIO_SAMPLING_88P2K    0x08
69*4882a593Smuzhiyun #define AUDIO_SAMPLING_64K      0x0B
70*4882a593Smuzhiyun #define AUDIO_SAMPLING_48K      0x02
71*4882a593Smuzhiyun #define AUDIO_SAMPLING_44P1K    0x00
72*4882a593Smuzhiyun #define AUDIO_SAMPLING_32K      0x03
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun #define REG_RX_AVI_HB1          0x13
75*4882a593Smuzhiyun #define REG_RX_AVI_HB2          0x12
76*4882a593Smuzhiyun #define REG_RX_AVI_DB0          0x14
77*4882a593Smuzhiyun #define REG_RX_AVI_DB1          0x15
78*4882a593Smuzhiyun #define REG_RX_AVI_DB2          0x16
79*4882a593Smuzhiyun #define REG_RX_AVI_DB3          0x17
80*4882a593Smuzhiyun #define REG_RX_AVI_DB4          0x18
81*4882a593Smuzhiyun #define REG_RX_AVI_DB5          0x19
82*4882a593Smuzhiyun #define REG_RX_AVI_DB6          0x1A
83*4882a593Smuzhiyun #define REG_RX_AVI_DB7          0x1B
84*4882a593Smuzhiyun #define REG_RX_AVI_DB8          0x1C
85*4882a593Smuzhiyun #define REG_RX_AVI_DB9          0x1D
86*4882a593Smuzhiyun #define REG_RX_AVI_DB10         0x1E
87*4882a593Smuzhiyun #define REG_RX_AVI_DB11         0x1F
88*4882a593Smuzhiyun #define REG_RX_AVI_DB12         0x20
89*4882a593Smuzhiyun #define REG_RX_AVI_DB13         0x21
90*4882a593Smuzhiyun #define REG_RX_AVI_DB14         0x22
91*4882a593Smuzhiyun #define REG_RX_AVI_DB15         0x23
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun #define DP_REG_INT_STS_07       0x07
94*4882a593Smuzhiyun #define DP_REG_INT_STS_08       0x08
95*4882a593Smuzhiyun #define DP_REG_INT_STS_09       0x09
96*4882a593Smuzhiyun #define DP_REG_INT_STS_0A       0x0A
97*4882a593Smuzhiyun #define DP_REG_INT_STS_0B       0x0B
98*4882a593Smuzhiyun #define DP_REG_INT_STS_0C       0x0C
99*4882a593Smuzhiyun #define DP_REG_INT_STS_0D       0x0D
100*4882a593Smuzhiyun #define DP_REG_INT_STS_0E       0x0E
101*4882a593Smuzhiyun #define DP_REG_INT_STS_0F       0x0F
102*4882a593Smuzhiyun #define DP_REG_INT_STS_2B       0x2B
103*4882a593Smuzhiyun #define DP_REG_INT_STS_2C       0x2C
104*4882a593Smuzhiyun #define DP_REG_INT_STS_2D       0x2D
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #define DP_REG_INT_MASK_07      0xD1
107*4882a593Smuzhiyun #define DP_REG_INT_MASK_08      0xD2
108*4882a593Smuzhiyun #define DP_REG_INT_MASK_09      0xD3
109*4882a593Smuzhiyun #define DP_REG_INT_MASK_0A      0xD4
110*4882a593Smuzhiyun #define DP_REG_INT_MASK_0B      0xD5
111*4882a593Smuzhiyun #define DP_REG_INT_MASK_0C      0xD6
112*4882a593Smuzhiyun #define DP_REG_INT_MASK_0D      0xD7
113*4882a593Smuzhiyun #define DP_REG_INT_MASK_0E      0xD8
114*4882a593Smuzhiyun #define DP_REG_INT_MASK_0F      0xD9
115*4882a593Smuzhiyun #define DP_REG_INT_MASK_10      0xDA
116*4882a593Smuzhiyun #define DP_REG_INT_MASK_11      0xDB
117*4882a593Smuzhiyun #define DP_REG_INT_MASK_2D      0xDC
118*4882a593Smuzhiyun #define DP_REG_INT_MASK_2C      0xDD
119*4882a593Smuzhiyun #define DP_REG_INT_MASK_2B      0xDE
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun #define BANK                    0x0F
122*4882a593Smuzhiyun #define BANKM                   0x07
123*4882a593Smuzhiyun #define FROM_CONFIG             0xFF
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun #define AUDIO_I2S_JUSTIFIED			AUDIO_I2S_MODE
126*4882a593Smuzhiyun // #define MIPI_TX_INTERFACE MIPI_DSI
127*4882a593Smuzhiyun #define MIPI_TX_INTERFACE			MIPI_CSI
128*4882a593Smuzhiyun #define MIPI_TX_LANE_SWAP			false
129*4882a593Smuzhiyun #define MIPI_TX_PN_SWAP				false
130*4882a593Smuzhiyun // #define MIPI_TX_DATA_TYPE DSI_RGB_24b
131*4882a593Smuzhiyun #define MIPI_TX_DATA_TYPE                       CSI_YCbCr4228b
132*4882a593Smuzhiyun #define MIPI_TX_ENABLE_AUTO_ADJUST_LANE_COUNT   false
133*4882a593Smuzhiyun /* HDMI_RX_VIDEO_STABLE_CONDITION_V_FRAME,
134*4882a593Smuzhiyun  * HDMI_RX_VIDEO_STABLE_CONDITION_CLOCK,
135*4882a593Smuzhiyun  * HDMI_RX_VIDEO_STABLE_CONDITION_H_LINE
136*4882a593Smuzhiyun  */
137*4882a593Smuzhiyun #define HDMI_RX_VIDEO_STABLE_CONDITION		HDMI_RX_VIDEO_STABLE_CONDITION_V_FRAME
138*4882a593Smuzhiyun /* MIPI_TX_NON_CONTINUOUS_CLOCK, MIPI_TX_CONTINUOUS_CLOCK */
139*4882a593Smuzhiyun #define MIPI_TX_ENABLE_CONTINUOUS_CLOCK		MIPI_TX_CONTINUOUS_CLOCK
140*4882a593Smuzhiyun #define MIPI_TX_ENABLE_DSI_SYNC_EVENT		false
141*4882a593Smuzhiyun #define MIPI_TX_ENABLE_DSI_EOTP_PACKET		false
142*4882a593Smuzhiyun #define MIPI_TX_ENABLE_INITIAL_FIRE_LP_CMD	true
143*4882a593Smuzhiyun #define DEFAULT_RS_LEVEL			0x9F
144*4882a593Smuzhiyun #define MIPI_TX_ENABLE_MANUAL_ADJUSTED_D_PHY	false
145*4882a593Smuzhiyun #define MIPI_TX_LPX				2
146*4882a593Smuzhiyun #define MIPI_TX_HS_PREPARE			0x02
147*4882a593Smuzhiyun #define MIPI_TX_HS_PREPARE_ZERO			0x04
148*4882a593Smuzhiyun #define MIPI_TX_HS_TRAIL			0x07
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun #define MAX_AUDIO_SAMPLING_FREQ_ERROR_COUNT	15
151*4882a593Smuzhiyun #define HDMI_RX_DISABLE_PIXEL_REPEAT		true
152*4882a593Smuzhiyun #define MIPI_TX_LANE_ADJUST_THRESHOLD		30
153*4882a593Smuzhiyun #define MIPI_TX_V_LPM_LENGTH			0x200
154*4882a593Smuzhiyun #define MIPI_TX_H_LPM_LENGTH			0x80
155*4882a593Smuzhiyun #define MIPI_TX_ENABLE_H_ENTER_LPM		false
156*4882a593Smuzhiyun #define MIPI_TX_ENABLE_HS_PRE_1T		true
157*4882a593Smuzhiyun #define MIPI_TX_ENABLE_PCLK_INV			false
158*4882a593Smuzhiyun #define MIPI_TX_ENABLE_MCLK_INV			true
159*4882a593Smuzhiyun #define MIPI_TX_ENABLE_BY_PASS			true
160*4882a593Smuzhiyun #define MIPI_TX_ENABLE_H_FIRE_PACKET		false
161*4882a593Smuzhiyun #define HDMI_RX_ENABLE_COLOR_UP_DN_FILTER	true
162*4882a593Smuzhiyun #define HDMI_RX_ENABLE_DITHER_FUNCTION		false
163*4882a593Smuzhiyun #define HDMI_RX_ENABLE_DITHER_FCNT_FUNCTION	false
164*4882a593Smuzhiyun #define HDMI_RX_COLOR_CLIP			true
165*4882a593Smuzhiyun #define HDMI_RX_CRCB_LIMIT			false
166*4882a593Smuzhiyun #define HDMI_RX_QUANT_4LB			true
167*4882a593Smuzhiyun #define HDMI_RX_AUTO_CSC_SELECT			false
168*4882a593Smuzhiyun #define LP_CMD_FIFO_SIZE			128
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun enum csc_matrix_type {
171*4882a593Smuzhiyun 	CSCMtx_RGB2YUV_ITU601_16_235,
172*4882a593Smuzhiyun 	CSCMtx_RGB2YUV_ITU601_00_255,
173*4882a593Smuzhiyun 	CSCMtx_RGB2YUV_ITU709_16_235,
174*4882a593Smuzhiyun 	CSCMtx_RGB2YUV_ITU709_00_255,
175*4882a593Smuzhiyun 	CSCMtx_YUV2RGB_ITU601_16_235,
176*4882a593Smuzhiyun 	CSCMtx_YUV2RGB_ITU601_00_255,
177*4882a593Smuzhiyun 	CSCMtx_YUV2RGB_ITU709_16_235,
178*4882a593Smuzhiyun 	CSCMtx_YUV2RGB_ITU709_00_255,
179*4882a593Smuzhiyun 	CSCMtx_YUV2RGB_BT2020_00_255,
180*4882a593Smuzhiyun 	CSCMtx_RGB_00_255_RGB_16_235,
181*4882a593Smuzhiyun 	CSCMtx_RGB_16_235_RGB_00_255,
182*4882a593Smuzhiyun 	CSCMtx_Unknown,
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun enum {
186*4882a593Smuzhiyun 	MIPI_CSI,
187*4882a593Smuzhiyun 	MIPI_DSI,
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun enum {
191*4882a593Smuzhiyun 	VSC_COLOR_RGB = 0x00,
192*4882a593Smuzhiyun 	VSC_COLOR_YUV444 = 0x01,
193*4882a593Smuzhiyun 	VSC_COLOR_YUV422 = 0x02,
194*4882a593Smuzhiyun 	VSC_COLOR_YUV420 = 0x03,
195*4882a593Smuzhiyun 	VSC_COLOR_YONLY,
196*4882a593Smuzhiyun 	VSC_COLOR_RAW,
197*4882a593Smuzhiyun 	VSC_COLOR_RESERVE
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun enum {
201*4882a593Smuzhiyun 	COLOR_RGB = 0x00,
202*4882a593Smuzhiyun 	COLOR_YUV422 = 0x01,
203*4882a593Smuzhiyun 	COLOR_YUV444 = 0x02,
204*4882a593Smuzhiyun 	COLOR_YUV420 = 0x03,
205*4882a593Smuzhiyun 	COLOR_RESERVE
206*4882a593Smuzhiyun };
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun enum {
209*4882a593Smuzhiyun 	COLORIMETRY_BT601 = 0x00,
210*4882a593Smuzhiyun 	COLORIMETRY_BT709 = 0x01,
211*4882a593Smuzhiyun 	COLORIMETRY_xvYCC601 = 0x02,
212*4882a593Smuzhiyun 	COLORIMETRY_xvYCC709 = 0x03,
213*4882a593Smuzhiyun 	COLORIMETRY_sYCC601 = 0x04,
214*4882a593Smuzhiyun 	COLORIMETRY_aYCC601 = 0x05,
215*4882a593Smuzhiyun 	COLORIMETRY_BT2020YcCbcCrc = 0x06,
216*4882a593Smuzhiyun 	COLORIMETRY_BT2020YCbCr = 0x07,
217*4882a593Smuzhiyun 	COLORIMETRY_RESERVE
218*4882a593Smuzhiyun };
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun enum {
221*4882a593Smuzhiyun 	COLORIMETRY_sRGB = 0x00,
222*4882a593Smuzhiyun 	COLORIMETRY_fixRGB = 0x01,
223*4882a593Smuzhiyun 	COLORIMETRY_scRGB = 0x02,
224*4882a593Smuzhiyun 	COLORIMETRY_aRGB = 0x03,
225*4882a593Smuzhiyun 	COLORIMETRY_DCIP3 = 0x04,
226*4882a593Smuzhiyun 	COLORIMETRY_CUSTOM = 0x05,
227*4882a593Smuzhiyun 	COLORIMETRY_BT2020RGB = 0x06
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun enum mipi_csi_data {
232*4882a593Smuzhiyun 	CSI_RGB10b = 0x25,
233*4882a593Smuzhiyun 	CSI_RGB888 = 0x24,
234*4882a593Smuzhiyun 	CSI_RGB666 = 0x23,
235*4882a593Smuzhiyun 	CSI_RGB565 = 0x22,
236*4882a593Smuzhiyun 	CSI_RGB555 = 0x21,
237*4882a593Smuzhiyun 	CSI_RGB444 = 0x20,
238*4882a593Smuzhiyun 	CSI_YCbCr4208b = 0x1A,
239*4882a593Smuzhiyun 	CSI_YCbCr4228b = 0x1E,
240*4882a593Smuzhiyun 	CSI_YCbCr42210b = 0x1F,
241*4882a593Smuzhiyun 	CSI_YCbCr42212b = 0x30
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun enum mipi_dsi_data {
245*4882a593Smuzhiyun 	DSI_RGB_24b = 0x3E,
246*4882a593Smuzhiyun 	DSI_RGB_30b = 0x0D,
247*4882a593Smuzhiyun 	DSI_RGB_36b = 0x1D,
248*4882a593Smuzhiyun 	DSI_RGB_18b = 0x1E,
249*4882a593Smuzhiyun 	DSI_RGB_18b_L = 0x2E,
250*4882a593Smuzhiyun 	DSI_YCbCr_16b = 0x2C,
251*4882a593Smuzhiyun 	DSI_YCbCr_20b = 0x0C,
252*4882a593Smuzhiyun 	DSI_YCbCr_24b = 0x1C
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun enum csc_select {
256*4882a593Smuzhiyun 	CSC_BYPASS =  0x00,
257*4882a593Smuzhiyun 	CSC_RGB2YUV = 0x02,
258*4882a593Smuzhiyun 	CSC_YUV2RGB = 0x03,
259*4882a593Smuzhiyun };
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun enum av_mute_state {
262*4882a593Smuzhiyun 	AV_MUTE_OFF,
263*4882a593Smuzhiyun 	AV_MUTE_ON,
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun enum {
267*4882a593Smuzhiyun 	AUDIO_OFF = 0x00,
268*4882a593Smuzhiyun 	AUDIO_I2S = 0x01,
269*4882a593Smuzhiyun 	AUDIO_SPDIF = 0x02,
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun enum {
273*4882a593Smuzhiyun 	AUDIO_I2S_MODE,
274*4882a593Smuzhiyun 	AUDIO_RIGHT_JUSTIFIED,
275*4882a593Smuzhiyun 	AUDIO_LEFT_JUSTIFIED,
276*4882a593Smuzhiyun };
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun enum {
279*4882a593Smuzhiyun 	MIPI_TX_NON_CONTINUOUS_CLOCK,
280*4882a593Smuzhiyun 	MIPI_TX_CONTINUOUS_CLOCK,
281*4882a593Smuzhiyun };
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun enum {
284*4882a593Smuzhiyun 	HDMI_RX_VIDEO_STABLE_CONDITION_V_FRAME,
285*4882a593Smuzhiyun 	HDMI_RX_VIDEO_STABLE_CONDITION_CLOCK,
286*4882a593Smuzhiyun 	HDMI_RX_VIDEO_STABLE_CONDITION_H_LINE,
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun enum dcs_cmd_name {
290*4882a593Smuzhiyun 	ENTER_SLEEP_MODE,
291*4882a593Smuzhiyun 	SET_DISPLAY_OFF,
292*4882a593Smuzhiyun 	EXIT_SLEEP_MODE,
293*4882a593Smuzhiyun 	SET_DISPLAY_ON,
294*4882a593Smuzhiyun 	GET_DISPLAY_MODE,
295*4882a593Smuzhiyun 	LONG_WRITE_CMD,
296*4882a593Smuzhiyun 	LONG_WRITE_CMD1,
297*4882a593Smuzhiyun 	DELAY,
298*4882a593Smuzhiyun };
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun enum mipi_lp_cmd_type {
301*4882a593Smuzhiyun 	LP_CMD_LPDT = 0x87,
302*4882a593Smuzhiyun 	LP_CMD_BTA = 0xFF,
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun enum mipi_packet_size {
306*4882a593Smuzhiyun 	SHORT_PACKET,
307*4882a593Smuzhiyun 	LONG_PACKET,
308*4882a593Smuzhiyun 	UNKNOWN_PACKET,
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun enum mipi_tx_lp_cmd_header {
312*4882a593Smuzhiyun 	NO_HEADER,
313*4882a593Smuzhiyun 	CALC_HEADER,
314*4882a593Smuzhiyun };
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static const s64 link_freq_menu_items[] = {
317*4882a593Smuzhiyun 	IT6616_LINK_FREQ,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun struct it6616_reg_set {
321*4882a593Smuzhiyun 	u8 ucAddr;
322*4882a593Smuzhiyun 	u8 andmask;
323*4882a593Smuzhiyun 	u8 ucValue;
324*4882a593Smuzhiyun };
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun struct bus_config {
327*4882a593Smuzhiyun 	u8 lane;
328*4882a593Smuzhiyun 	u8 type;
329*4882a593Smuzhiyun 	u8 reg23_p2m;
330*4882a593Smuzhiyun 	u8 regb0_div[3];
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun union tx_p2m_delay {
334*4882a593Smuzhiyun 	u8 tx_dsi_vsync_delay;
335*4882a593Smuzhiyun 	u8 tx_csi_p2m_delay;
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun struct bus_para {
339*4882a593Smuzhiyun 	struct bus_config cfg;
340*4882a593Smuzhiyun 	u8 swap_pn;
341*4882a593Smuzhiyun 	u8 swap_lan;
342*4882a593Smuzhiyun 	u8 pclk_inv;
343*4882a593Smuzhiyun 	u8 mclk_inv;
344*4882a593Smuzhiyun 	u8 lpx_num;
345*4882a593Smuzhiyun 	u8 mipi_tx_hs_prepare;
346*4882a593Smuzhiyun 	u8 tx_sel_line_start;
347*4882a593Smuzhiyun 	u8 tx_bypass;
348*4882a593Smuzhiyun 	u8 tx_enable_hs_pre_1T;
349*4882a593Smuzhiyun 	u8 tx_enable_h_enter_lpm;
350*4882a593Smuzhiyun 	u8 tx_vsync_delay;
351*4882a593Smuzhiyun 	union tx_p2m_delay p2m_delay;
352*4882a593Smuzhiyun 	u16 tx_vlpm_length;
353*4882a593Smuzhiyun 	u16 tx_hlpm_length;
354*4882a593Smuzhiyun };
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun struct mipi_bus {
357*4882a593Smuzhiyun 	u8 lane_cnt;
358*4882a593Smuzhiyun 	u8 data_type;
359*4882a593Smuzhiyun 	u8 bus_type;
360*4882a593Smuzhiyun 	u32 mbus_fmt_code;
361*4882a593Smuzhiyun 	struct bus_para bus_para_config;
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun struct mipi_packet_size_data_id_map {
365*4882a593Smuzhiyun 	u8 data_id;
366*4882a593Smuzhiyun 	enum mipi_packet_size packet_size;
367*4882a593Smuzhiyun };
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun struct mipi_packet_size_data_id_map packet_size_data_id_map[] = {
370*4882a593Smuzhiyun 	{0x05, SHORT_PACKET},/* dcs short write without parameter */
371*4882a593Smuzhiyun 	{0x15, SHORT_PACKET},/* dcs short write with one parameter */
372*4882a593Smuzhiyun 	{0x23, SHORT_PACKET},/* generic short write, 2 parameters */
373*4882a593Smuzhiyun 	{0x29, LONG_PACKET},/* generic long write */
374*4882a593Smuzhiyun 	{0x39, LONG_PACKET},/* dcs long write */
375*4882a593Smuzhiyun 	{0x06, SHORT_PACKET},
376*4882a593Smuzhiyun 	{0x16, SHORT_PACKET},
377*4882a593Smuzhiyun 	{0x37, SHORT_PACKET},
378*4882a593Smuzhiyun 	{0x03, SHORT_PACKET},
379*4882a593Smuzhiyun 	{0x13, SHORT_PACKET},
380*4882a593Smuzhiyun 	{0x04, SHORT_PACKET},
381*4882a593Smuzhiyun 	{0x14, SHORT_PACKET},
382*4882a593Smuzhiyun 	{0x24, SHORT_PACKET}
383*4882a593Smuzhiyun };
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun struct mipi_packet {
386*4882a593Smuzhiyun 	u8 data_id;
387*4882a593Smuzhiyun 	u8 word_count_l;
388*4882a593Smuzhiyun 	u8 word_count_h;
389*4882a593Smuzhiyun 	u8 ecc;
390*4882a593Smuzhiyun };
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun struct dcs_setting_entry {
393*4882a593Smuzhiyun 	enum dcs_cmd_name cmd_name;
394*4882a593Smuzhiyun 	enum mipi_lp_cmd_type cmd;
395*4882a593Smuzhiyun 	u8 data_id;
396*4882a593Smuzhiyun 	u8 count;
397*4882a593Smuzhiyun 	u8 para_list[LP_CMD_FIFO_SIZE];
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun static const struct dcs_setting_entry dcs_table[] = {
401*4882a593Smuzhiyun 	{	/* command 0x10 with no parameter, checksum: 0x2C */
402*4882a593Smuzhiyun 		ENTER_SLEEP_MODE, LP_CMD_LPDT, 0x05, 2, {0x10, 0x00}
403*4882a593Smuzhiyun 	}, {	/* command 0x28 with no parameter, checksum: 0x06 */
404*4882a593Smuzhiyun 		SET_DISPLAY_OFF, LP_CMD_LPDT, 0x05, 2, {0x28, 0x00}
405*4882a593Smuzhiyun 	}, {	/* command 0x11 with no parameter, checksum: 0x36 */
406*4882a593Smuzhiyun 		EXIT_SLEEP_MODE, LP_CMD_LPDT, 0x05, 2, {0x11, 0x00}
407*4882a593Smuzhiyun 	}, {	/* command 0x29 with no parameter, checksum: 0x1C */
408*4882a593Smuzhiyun 		SET_DISPLAY_ON, LP_CMD_LPDT, 0x05, 2, {0x29, 0x00}
409*4882a593Smuzhiyun 	}, {	/* checksum: 0x1A */
410*4882a593Smuzhiyun 		GET_DISPLAY_MODE, LP_CMD_LPDT, 0x06, 2, {0x0D, 0x00}
411*4882a593Smuzhiyun 	}, {	/* command 0x50 with 2 parameters */
412*4882a593Smuzhiyun 		LONG_WRITE_CMD, LP_CMD_LPDT, 0x39, 3, {0x50, 0x5A, 0x09}
413*4882a593Smuzhiyun 	}, {	/* command 0x80 with 16 parameters */
414*4882a593Smuzhiyun 		LONG_WRITE_CMD1, LP_CMD_LPDT, 0x29, 17,
415*4882a593Smuzhiyun 		{0x80, 0x5A, 0x51, 0xB5, 0x2A, 0x6C, 0x35,
416*4882a593Smuzhiyun 		0x4B, 0x01, 0x40, 0xE1, 0x0D, 0x82, 0x20, 0x08, 0x30, 0x03}
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun };
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun static const int code_to_rate_table[] = {
421*4882a593Smuzhiyun 	44100, 0, 48000, 32000, 0, 384000, 0, 0, 88200,
422*4882a593Smuzhiyun 	768000, 96000, 64000, 176400, 0, 192000, 0, 0, 0,
423*4882a593Smuzhiyun 	0, 0, 0, 0, 0, 0, 0, 0, 0, 256000, 0, 0, 0, 0, 0,
424*4882a593Smuzhiyun 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128000, 0, 0, 0, 0,
425*4882a593Smuzhiyun 	0, 0, 0, 0, 0, 1024000, 0, 0, 0, 0, 0, 512000
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun struct color_format {
429*4882a593Smuzhiyun 	unsigned char color_mode;
430*4882a593Smuzhiyun 	unsigned char color_depth;
431*4882a593Smuzhiyun 	unsigned char color_cea_range;
432*4882a593Smuzhiyun 	unsigned char color_colorietry;
433*4882a593Smuzhiyun 	unsigned char color_ex_colorietry;
434*4882a593Smuzhiyun 	unsigned char content_type;
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun struct video_info {
438*4882a593Smuzhiyun 	u16 h_active;
439*4882a593Smuzhiyun 	u16 v_active;
440*4882a593Smuzhiyun 	u16 h_total;
441*4882a593Smuzhiyun 	u16 v_total;
442*4882a593Smuzhiyun 	u32 pclk;
443*4882a593Smuzhiyun 	u32 TMDSCLK;
444*4882a593Smuzhiyun 	u32 frame_rate;
445*4882a593Smuzhiyun 	u16 h_front_porch;
446*4882a593Smuzhiyun 	u16 h_sync_w;
447*4882a593Smuzhiyun 	u16 h_back_porch;
448*4882a593Smuzhiyun 	u16 v_front_porch;
449*4882a593Smuzhiyun 	u16 v_sync_w;
450*4882a593Smuzhiyun 	u16 v_back_porch;
451*4882a593Smuzhiyun 	u16 interlaced;
452*4882a593Smuzhiyun 	u16 v_sync_pol;
453*4882a593Smuzhiyun 	u16 h_sync_pol;
454*4882a593Smuzhiyun 	u16 ColorDepth;
455*4882a593Smuzhiyun 	u16 VIC;
456*4882a593Smuzhiyun };
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun struct audio_info {
459*4882a593Smuzhiyun 	u32 n;
460*4882a593Smuzhiyun 	u32 cts;
461*4882a593Smuzhiyun 	u8 channel_status;
462*4882a593Smuzhiyun 	u32 sample_freq;
463*4882a593Smuzhiyun 	u32 force_sample_freq;
464*4882a593Smuzhiyun };
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun struct it6616 {
467*4882a593Smuzhiyun 	struct i2c_client *hdmi_i2c;
468*4882a593Smuzhiyun 	struct i2c_client *mipi_i2c;
469*4882a593Smuzhiyun 	struct i2c_client *edid_i2c;
470*4882a593Smuzhiyun 	struct regmap *hdmi_regmap;
471*4882a593Smuzhiyun 	struct regmap *mipi_regmap;
472*4882a593Smuzhiyun 	struct regmap *edid_regmap;
473*4882a593Smuzhiyun 	u8 attr_hdmi_reg_bank;
474*4882a593Smuzhiyun 	struct class *hdmirx_class;
475*4882a593Smuzhiyun 	struct device *dev;
476*4882a593Smuzhiyun 	struct device *classdev;
477*4882a593Smuzhiyun 	struct v4l2_fwnode_bus_mipi_csi2 bus;
478*4882a593Smuzhiyun 	struct v4l2_subdev sd;
479*4882a593Smuzhiyun 	struct media_pad pad;
480*4882a593Smuzhiyun 	struct v4l2_ctrl_handler hdl;
481*4882a593Smuzhiyun 	struct i2c_client *i2c_client;
482*4882a593Smuzhiyun 	struct mutex confctl_mutex;
483*4882a593Smuzhiyun 	struct v4l2_ctrl *detect_tx_5v_ctrl;
484*4882a593Smuzhiyun 	struct v4l2_ctrl *audio_sampling_rate_ctrl;
485*4882a593Smuzhiyun 	struct v4l2_ctrl *audio_present_ctrl;
486*4882a593Smuzhiyun 	struct v4l2_ctrl *link_freq;
487*4882a593Smuzhiyun 	struct v4l2_ctrl *pixel_rate;
488*4882a593Smuzhiyun 	struct v4l2_dv_timings timings;
489*4882a593Smuzhiyun 	struct clk *xvclk;
490*4882a593Smuzhiyun 	struct gpio_desc *reset_gpio;
491*4882a593Smuzhiyun 	struct gpio_desc *power_gpio;
492*4882a593Smuzhiyun 	struct delayed_work work_i2c_poll;
493*4882a593Smuzhiyun 	const char *module_facing;
494*4882a593Smuzhiyun 	const char *module_name;
495*4882a593Smuzhiyun 	const char *len_name;
496*4882a593Smuzhiyun 	const struct it6616_mode *cur_mode;
497*4882a593Smuzhiyun 	bool nosignal;
498*4882a593Smuzhiyun 	bool is_audio_present;
499*4882a593Smuzhiyun 	u32 mbus_fmt_code;
500*4882a593Smuzhiyun 	u8 csi_lanes_in_use;
501*4882a593Smuzhiyun 	u32 module_index;
502*4882a593Smuzhiyun 	u32 audio_sampling_rate;
503*4882a593Smuzhiyun 	bool hdmi_rx_video_stable;
504*4882a593Smuzhiyun 	bool hdmi_rx_hdcp_state;
505*4882a593Smuzhiyun 	bool mipi_tx_video_stable;
506*4882a593Smuzhiyun 	bool mipi_tx_enable_manual_adjusted_d_phy;
507*4882a593Smuzhiyun 	u8 audio_stable;
508*4882a593Smuzhiyun 	u8 audio_interface;
509*4882a593Smuzhiyun 	u8 rs_level;
510*4882a593Smuzhiyun 	struct mipi_bus mipi;
511*4882a593Smuzhiyun 	struct color_format color_fmt;
512*4882a593Smuzhiyun 	struct video_info vinfo;
513*4882a593Smuzhiyun 	struct audio_info ainfo;
514*4882a593Smuzhiyun 	u8 edid_data[256];
515*4882a593Smuzhiyun 	u16 edid_len;
516*4882a593Smuzhiyun 	u8 audio_sampling_freq_error_count;
517*4882a593Smuzhiyun 	u8 audio_i2s_justified;
518*4882a593Smuzhiyun 	u8 mipi_tx_enable_auto_adjust_lane_count;
519*4882a593Smuzhiyun 	u8 mipi_tx_enable_h_fire_packet;
520*4882a593Smuzhiyun 	u8 mipi_tx_enable_initial_fire_lp_cmd;
521*4882a593Smuzhiyun 	u8 hdmi_rx_disable_pixel_repeat;
522*4882a593Smuzhiyun 	bool mipi_tx_enable_continuous_clock;
523*4882a593Smuzhiyun 	u8 mipi_tx_enable_mipi_output;
524*4882a593Smuzhiyun 	u8 hdmi_rx_video_stable_condition;
525*4882a593Smuzhiyun 	bool	power_on;
526*4882a593Smuzhiyun 	u32 rclk;
527*4882a593Smuzhiyun 	u32 tx_mclk;
528*4882a593Smuzhiyun 	u32 tx_rclk;
529*4882a593Smuzhiyun 	u32 tx_pclk;
530*4882a593Smuzhiyun 	u32 tx_mclk_ps;
531*4882a593Smuzhiyun 	struct hdmi_avi_infoframe avi_if;
532*4882a593Smuzhiyun 	struct hdmi_avi_infoframe avi_if_prev;
533*4882a593Smuzhiyun 	enum hdmi_colorspace output_colorspace;
534*4882a593Smuzhiyun };
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun static const struct v4l2_dv_timings_cap it6616_timings_cap = {
537*4882a593Smuzhiyun 	.type = V4L2_DV_BT_656_1120,
538*4882a593Smuzhiyun 	.reserved = { 0 },
539*4882a593Smuzhiyun 	V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 400000000,
540*4882a593Smuzhiyun 			V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
541*4882a593Smuzhiyun 			V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
542*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED |
543*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_REDUCED_BLANKING |
544*4882a593Smuzhiyun 			V4L2_DV_BT_CAP_CUSTOM)
545*4882a593Smuzhiyun };
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun struct it6616_mode {
548*4882a593Smuzhiyun 	u32 width;
549*4882a593Smuzhiyun 	u32 height;
550*4882a593Smuzhiyun 	struct v4l2_fract max_fps;
551*4882a593Smuzhiyun 	u32 hts_def;
552*4882a593Smuzhiyun 	u32 vts_def;
553*4882a593Smuzhiyun 	u32 exp_def;
554*4882a593Smuzhiyun };
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun static const struct it6616_mode supported_modes[] = {
557*4882a593Smuzhiyun 	{
558*4882a593Smuzhiyun 		.width = 3840,
559*4882a593Smuzhiyun 		.height = 2160,
560*4882a593Smuzhiyun 		.max_fps = {
561*4882a593Smuzhiyun 			.numerator = 10000,
562*4882a593Smuzhiyun 			.denominator = 300000,
563*4882a593Smuzhiyun 		},
564*4882a593Smuzhiyun 		.hts_def = 4400,
565*4882a593Smuzhiyun 		.vts_def = 2250,
566*4882a593Smuzhiyun 	}, {
567*4882a593Smuzhiyun 		.width = 1920,
568*4882a593Smuzhiyun 		.height = 1080,
569*4882a593Smuzhiyun 		.max_fps = {
570*4882a593Smuzhiyun 			.numerator = 10000,
571*4882a593Smuzhiyun 			.denominator = 600000,
572*4882a593Smuzhiyun 		},
573*4882a593Smuzhiyun 		.hts_def = 2200,
574*4882a593Smuzhiyun 		.vts_def = 1125,
575*4882a593Smuzhiyun 	}, {
576*4882a593Smuzhiyun 		.width = 1920,
577*4882a593Smuzhiyun 		.height = 540,
578*4882a593Smuzhiyun 		.max_fps = {
579*4882a593Smuzhiyun 			.numerator = 10000,
580*4882a593Smuzhiyun 			.denominator = 600000,
581*4882a593Smuzhiyun 		},
582*4882a593Smuzhiyun 		.hts_def = 2200,
583*4882a593Smuzhiyun 		.vts_def = 562,
584*4882a593Smuzhiyun 	}, {
585*4882a593Smuzhiyun 		.width = 1280,
586*4882a593Smuzhiyun 		.height = 720,
587*4882a593Smuzhiyun 		.max_fps = {
588*4882a593Smuzhiyun 			.numerator = 10000,
589*4882a593Smuzhiyun 			.denominator = 600000,
590*4882a593Smuzhiyun 		},
591*4882a593Smuzhiyun 		.hts_def = 1650,
592*4882a593Smuzhiyun 		.vts_def = 750,
593*4882a593Smuzhiyun 	}, {
594*4882a593Smuzhiyun 		.width = 720,
595*4882a593Smuzhiyun 		.height = 576,
596*4882a593Smuzhiyun 		.max_fps = {
597*4882a593Smuzhiyun 			.numerator = 10000,
598*4882a593Smuzhiyun 			.denominator = 500000,
599*4882a593Smuzhiyun 		},
600*4882a593Smuzhiyun 		.hts_def = 864,
601*4882a593Smuzhiyun 		.vts_def = 625,
602*4882a593Smuzhiyun 	}, {
603*4882a593Smuzhiyun 		.width = 720,
604*4882a593Smuzhiyun 		.height = 480,
605*4882a593Smuzhiyun 		.max_fps = {
606*4882a593Smuzhiyun 			.numerator = 10000,
607*4882a593Smuzhiyun 			.denominator = 600000,
608*4882a593Smuzhiyun 		},
609*4882a593Smuzhiyun 		.hts_def = 858,
610*4882a593Smuzhiyun 		.vts_def = 525,
611*4882a593Smuzhiyun 	}, {
612*4882a593Smuzhiyun 		.width = 720,
613*4882a593Smuzhiyun 		.height = 288,
614*4882a593Smuzhiyun 		.max_fps = {
615*4882a593Smuzhiyun 			.numerator = 10000,
616*4882a593Smuzhiyun 			.denominator = 500000,
617*4882a593Smuzhiyun 		},
618*4882a593Smuzhiyun 		.hts_def = 864,
619*4882a593Smuzhiyun 		.vts_def = 312,
620*4882a593Smuzhiyun 	}, {
621*4882a593Smuzhiyun 		.width = 720,
622*4882a593Smuzhiyun 		.height = 240,
623*4882a593Smuzhiyun 		.max_fps = {
624*4882a593Smuzhiyun 			.numerator = 10000,
625*4882a593Smuzhiyun 			.denominator = 600000,
626*4882a593Smuzhiyun 		},
627*4882a593Smuzhiyun 		.hts_def = 858,
628*4882a593Smuzhiyun 		.vts_def = 262,
629*4882a593Smuzhiyun 	},
630*4882a593Smuzhiyun };
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun static const u8 default_edid[] = {
633*4882a593Smuzhiyun 	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
634*4882a593Smuzhiyun 	0x49, 0x78, 0x01, 0x88, 0x00, 0x88, 0x88, 0x88,
635*4882a593Smuzhiyun 	0x1C, 0x1F, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,
636*4882a593Smuzhiyun 	0x0A, 0x0D, 0xC9, 0xA0, 0x57, 0x47, 0x98, 0x27,
637*4882a593Smuzhiyun 	0x12, 0x48, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x01,
638*4882a593Smuzhiyun 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
639*4882a593Smuzhiyun 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
640*4882a593Smuzhiyun 	0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
641*4882a593Smuzhiyun 	0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E,
642*4882a593Smuzhiyun 	0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20,
643*4882a593Smuzhiyun 	0x6E, 0x28, 0x55, 0x00, 0xC4, 0x8E, 0x21, 0x00,
644*4882a593Smuzhiyun 	0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x54,
645*4882a593Smuzhiyun 	0x37, 0x34, 0x39, 0x2D, 0x66, 0x48, 0x44, 0x37,
646*4882a593Smuzhiyun 	0x32, 0x30, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD,
647*4882a593Smuzhiyun 	0x00, 0x14, 0x78, 0x01, 0xFF, 0x1D, 0x00, 0x0A,
648*4882a593Smuzhiyun 	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x64,
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	0x02, 0x03, 0x1C, 0x71, 0x49, 0x90, 0x04, 0x02,
651*4882a593Smuzhiyun 	0x5F, 0x11, 0x07, 0x05, 0x16, 0x22, 0x23, 0x09,
652*4882a593Smuzhiyun 	0x07, 0x01, 0x83, 0x01, 0x00, 0x00, 0x65, 0x03,
653*4882a593Smuzhiyun 	0x0C, 0x00, 0x10, 0x00, 0x8C, 0x0A, 0xD0, 0x8A,
654*4882a593Smuzhiyun 	0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00,
655*4882a593Smuzhiyun 	0x13, 0x8E, 0x21, 0x00, 0x00, 0x1E, 0xD8, 0x09,
656*4882a593Smuzhiyun 	0x80, 0xA0, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x60,
657*4882a593Smuzhiyun 	0xA2, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x18,
658*4882a593Smuzhiyun 	0x8C, 0x0A, 0xD0, 0x90, 0x20, 0x40, 0x31, 0x20,
659*4882a593Smuzhiyun 	0x0C, 0x40, 0x55, 0x00, 0x48, 0x39, 0x00, 0x00,
660*4882a593Smuzhiyun 	0x00, 0x18, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x38,
661*4882a593Smuzhiyun 	0x2D, 0x40, 0x58, 0x2C, 0x45, 0x00, 0xC0, 0x6C,
662*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x18, 0x01, 0x1D, 0x80, 0x18,
663*4882a593Smuzhiyun 	0x71, 0x1C, 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00,
664*4882a593Smuzhiyun 	0xC0, 0x6C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
665*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3,
666*4882a593Smuzhiyun };
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun static const struct bus_config it6616_csi_bus_cfg[] = {
669*4882a593Smuzhiyun 	{4, CSI_RGB10b, 0x8F, {0xEE, 0xEE, 0xEE}},
670*4882a593Smuzhiyun 	{4, CSI_RGB888, 0x23, {0x65, 0x22, 0x22}},
671*4882a593Smuzhiyun 	{4, CSI_RGB666, 0x89, {0xE8, 0xE8, 0xE8}},
672*4882a593Smuzhiyun 	{4, CSI_RGB565, 0x22, {0x63, 0x21, 0x00}},
673*4882a593Smuzhiyun 	{4, CSI_RGB555, 0x22, {0x63, 0x21, 0x00}},
674*4882a593Smuzhiyun 	{4, CSI_RGB444, 0x22, {0x63, 0x21, 0x00}},
675*4882a593Smuzhiyun 	{4, CSI_YCbCr4208b, 0x23, {0x65, 0x22, 0x22}},
676*4882a593Smuzhiyun 	{4, CSI_YCbCr4228b, 0x22, {0x63, 0x21, 0x00}},
677*4882a593Smuzhiyun 	{4, CSI_YCbCr42210b, 0x45, {0x64, 0x64, 0x64}},
678*4882a593Smuzhiyun 	{4, CSI_YCbCr42212b, 0x23, {0x65, 0x22, 0x22}},
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	{2, CSI_RGB10b, 0x4F, {0x6E, 0x6E, 0x6E}},
681*4882a593Smuzhiyun 	{2, CSI_RGB888, 0x13, {0x6B, 0x25, 0x25}},
682*4882a593Smuzhiyun 	{2, CSI_RGB666, 0x49, {0x68, 0x68, 0x68}},
683*4882a593Smuzhiyun 	{2, CSI_RGB565, 0x12, {0x67, 0x23, 0x01}},
684*4882a593Smuzhiyun 	{2, CSI_RGB555, 0x12, {0x67, 0x23, 0x01}},
685*4882a593Smuzhiyun 	{2, CSI_RGB444, 0x12, {0x67, 0x23, 0x01}},
686*4882a593Smuzhiyun 	{2, CSI_YCbCr4208b, 0x13, {0x6B, 0x25, 0x25}},
687*4882a593Smuzhiyun 	{2, CSI_YCbCr4228b, 0x12, {0x67, 0x23, 0x01}},
688*4882a593Smuzhiyun 	{2, CSI_YCbCr42210b, 0x25, {0x69, 0x24, 0x24}},
689*4882a593Smuzhiyun 	{2, CSI_YCbCr42212b, 0x13, {0x6B, 0x25, 0x25}},
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	{1, CSI_RGB10b, 0x2F, {0x7D, 0x2E, 0x2E}},
692*4882a593Smuzhiyun 	{1, CSI_RGB888, 0x03, {0x77, 0x2B, 0x05}},
693*4882a593Smuzhiyun 	{1, CSI_RGB666, 0x29, {0x71, 0x28, 0x28}},
694*4882a593Smuzhiyun 	{1, CSI_RGB565, 0x02, {0x6F, 0x27, 0x03}},
695*4882a593Smuzhiyun 	{1, CSI_RGB555, 0x02, {0x6F, 0x27, 0x03}},
696*4882a593Smuzhiyun 	{1, CSI_RGB444, 0x02, {0x6F, 0x27, 0x03}},
697*4882a593Smuzhiyun 	{1, CSI_YCbCr4208b, 0x03, {0x77, 0x2B, 0x05}},
698*4882a593Smuzhiyun 	{1, CSI_YCbCr4228b, 0x02, {0x6F, 0x27, 0x03}},
699*4882a593Smuzhiyun 	{1, CSI_YCbCr42210b, 0x15, {0x73, 0x29, 0x04}},
700*4882a593Smuzhiyun 	{1, CSI_YCbCr42212b,  0x03, {0x77, 0x2B, 0x05}},
701*4882a593Smuzhiyun 	{0, 0, 0, {0, 0, 0}},
702*4882a593Smuzhiyun };
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun static const struct bus_config it6616_dsi_bus_cfg[] = {
705*4882a593Smuzhiyun 	{4, DSI_RGB_36b, 0x19, {0x68, 0x68, 0x68}},
706*4882a593Smuzhiyun 	{4, DSI_RGB_30b, 0x2F, {0xEE, 0xEE, 0xEE}},
707*4882a593Smuzhiyun 	{4, DSI_RGB_24b, 0x03, {0x65, 0x22, 0x22}},
708*4882a593Smuzhiyun 	{4, DSI_RGB_18b_L, 0x03, {0x65, 0x22, 0x22}},
709*4882a593Smuzhiyun 	{4, DSI_RGB_18b, 0x29, {0xE8, 0xE8, 0xE8}},
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	{2, DSI_RGB_36b, 0x19, {0x71, 0x28, 0x28}},
712*4882a593Smuzhiyun 	{2, DSI_RGB_30b, 0x2F, {0x6E, 0x6E, 0x6E}},
713*4882a593Smuzhiyun 	{2, DSI_RGB_24b, 0x03, {0x6B, 0x25, 0x25}},
714*4882a593Smuzhiyun 	{2, DSI_RGB_18b_L, 0x03, {0x6B, 0x25, 0x25}},
715*4882a593Smuzhiyun 	{2, DSI_RGB_18b, 0x29, {0x68, 0x68, 0x68}},
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	{1, DSI_RGB_36b, 0x19, {0x31, 0x31, 0x08}},
718*4882a593Smuzhiyun 	{1, DSI_RGB_30b, 0x2F, {0x7D, 0x2E, 0x2E}},
719*4882a593Smuzhiyun 	{1, DSI_RGB_24b, 0x03, {0x77, 0x2B, 0x05}},
720*4882a593Smuzhiyun 	{1, DSI_RGB_18b_L, 0x03, {0x77, 0x2B, 0x05}},
721*4882a593Smuzhiyun 	{1, DSI_RGB_18b, 0x29, {0x71, 0x28, 0x28}},
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	//add in D0 yuv422
724*4882a593Smuzhiyun 	{4, DSI_YCbCr_16b, 0x02, {0x63, 0x21, 0x00}},
725*4882a593Smuzhiyun 	{4, DSI_YCbCr_20b, 0x03, {0x65, 0x22, 0x22}},
726*4882a593Smuzhiyun 	{4, DSI_YCbCr_24b, 0x03, {0x65, 0x22, 0x22}},
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	{2, DSI_YCbCr_16b, 0x02, {0x67, 0x23, 0x01}},
729*4882a593Smuzhiyun 	{2, DSI_YCbCr_20b, 0x03, {0x6B, 0x25, 0x25}},
730*4882a593Smuzhiyun 	{2, DSI_YCbCr_24b, 0x03, {0x6B, 0x25, 0x25}},
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	{1, DSI_YCbCr_16b, 0x02, {0x6F, 0x27, 0x03}},
733*4882a593Smuzhiyun 	{1, DSI_YCbCr_20b, 0x03, {0x77, 0x2B, 0x05}},
734*4882a593Smuzhiyun 	{1, DSI_YCbCr_24b, 0x03, {0x77, 0x2B, 0x05}},
735*4882a593Smuzhiyun 	{0, 0, 0, {0, 0, 0}},
736*4882a593Smuzhiyun };
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun static const u8 mipi_color_space[][10] = {
739*4882a593Smuzhiyun 	{
740*4882a593Smuzhiyun 		CSI_RGB10b,
741*4882a593Smuzhiyun 		CSI_RGB888,
742*4882a593Smuzhiyun 		CSI_RGB666,
743*4882a593Smuzhiyun 		CSI_RGB565,
744*4882a593Smuzhiyun 		CSI_RGB555,
745*4882a593Smuzhiyun 		CSI_RGB444,
746*4882a593Smuzhiyun 		CSI_YCbCr4208b,
747*4882a593Smuzhiyun 		CSI_YCbCr4228b,
748*4882a593Smuzhiyun 		CSI_YCbCr42210b,
749*4882a593Smuzhiyun 		CSI_YCbCr42212b
750*4882a593Smuzhiyun 	}, {
751*4882a593Smuzhiyun 		DSI_RGB_36b,
752*4882a593Smuzhiyun 		DSI_RGB_30b,
753*4882a593Smuzhiyun 		DSI_RGB_24b,
754*4882a593Smuzhiyun 		DSI_RGB_18b_L,
755*4882a593Smuzhiyun 		DSI_RGB_18b,
756*4882a593Smuzhiyun 		DSI_YCbCr_16b,
757*4882a593Smuzhiyun 		DSI_YCbCr_20b,
758*4882a593Smuzhiyun 		DSI_YCbCr_24b,
759*4882a593Smuzhiyun 		0xFF,
760*4882a593Smuzhiyun 		0xFF
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun };
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun static char *mipi_color_space_name[][10] = {
765*4882a593Smuzhiyun 	{
766*4882a593Smuzhiyun 		"CSI_RGB10b",
767*4882a593Smuzhiyun 		"CSI_RGB888",
768*4882a593Smuzhiyun 		"CSI_RGB666",
769*4882a593Smuzhiyun 		"CSI_RGB565",
770*4882a593Smuzhiyun 		"CSI_RGB555",
771*4882a593Smuzhiyun 		"CSI_RGB444",
772*4882a593Smuzhiyun 		"CSI_YCbCr4208b",
773*4882a593Smuzhiyun 		"CSI_YCbCr4228b",
774*4882a593Smuzhiyun 		"CSI_YCbCr42210b",
775*4882a593Smuzhiyun 		"CSI_YCbCr42212b"
776*4882a593Smuzhiyun 	}, {
777*4882a593Smuzhiyun 		"DSI_RGB_36b",
778*4882a593Smuzhiyun 		"DSI_RGB_30b",
779*4882a593Smuzhiyun 		"DSI_RGB_24b",
780*4882a593Smuzhiyun 		"DSI_RGB_18b_L",
781*4882a593Smuzhiyun 		"DSI_RGB_18b",
782*4882a593Smuzhiyun 		"DSI_YCbCr_16b",
783*4882a593Smuzhiyun 		"DSI_YCbCr_20b",
784*4882a593Smuzhiyun 		"DSI_YCbCr_24b",
785*4882a593Smuzhiyun 		"can not find color space",
786*4882a593Smuzhiyun 		"can not find color space"
787*4882a593Smuzhiyun 	}
788*4882a593Smuzhiyun };
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun static const u8 csc_matrix[][22] = {
791*4882a593Smuzhiyun 	{
792*4882a593Smuzhiyun 		0x00, 0x80, 0x10, 0xB2, 0x04, 0x65, 0x02, 0xE9, 0x00, 0x93, 0x3C,
793*4882a593Smuzhiyun 		0x18, 0x04, 0x55, 0x3F, 0x49, 0x3D, 0x9F, 0x3E, 0x18, 0x04, 0x00
794*4882a593Smuzhiyun 	}, {
795*4882a593Smuzhiyun 		0x10, 0x80, 0x10, 0x09, 0x04, 0x0E, 0x02, 0xC9, 0x00, 0x0F, 0x3D,
796*4882a593Smuzhiyun 		0x84, 0x03, 0x6D, 0x3F, 0xAB, 0x3D, 0xD1, 0x3E, 0x84, 0x03, 0x00
797*4882a593Smuzhiyun 	}, {
798*4882a593Smuzhiyun 		0x00, 0x80, 0x10, 0xB8, 0x05, 0xB4, 0x01, 0x94, 0x00, 0x4A, 0x3C,
799*4882a593Smuzhiyun 		0x17, 0x04, 0x9F, 0x3F, 0xD9, 0x3C, 0x10, 0x3F, 0x17, 0x04, 0x00
800*4882a593Smuzhiyun 	}, {
801*4882a593Smuzhiyun 		0x10, 0x80, 0x10, 0xEA, 0x04, 0x77, 0x01, 0x7F, 0x00, 0xD0, 0x3C,
802*4882a593Smuzhiyun 		0x83, 0x03, 0xAD, 0x3F, 0x4B, 0x3D, 0x32, 0x3F, 0x83, 0x03, 0x00
803*4882a593Smuzhiyun 	}, {
804*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00, 0x08, 0x6B, 0x3A, 0x50, 0x3D, 0x00, 0x08,
805*4882a593Smuzhiyun 		0xF5, 0x0A, 0x02, 0x00, 0x00, 0x08, 0xFD, 0x3F, 0xDA, 0x0D, 0x00
806*4882a593Smuzhiyun 	}, {
807*4882a593Smuzhiyun 		0x04, 0x00, 0xA7, 0x4F, 0x09, 0x81, 0x39, 0xDD, 0x3C, 0x4F, 0x09,
808*4882a593Smuzhiyun 		0xC4, 0x0C, 0x01, 0x00, 0x4F, 0x09, 0xFD, 0x3F, 0x1F, 0x10, 0x00
809*4882a593Smuzhiyun 	}, {
810*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00, 0x08, 0x55, 0x3C, 0x88, 0x3E, 0x00, 0x08,
811*4882a593Smuzhiyun 		0x51, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x84, 0x0E, 0x00
812*4882a593Smuzhiyun 	}, {
813*4882a593Smuzhiyun 		0x04, 0x00, 0xA7, 0x4F, 0x09, 0xBA, 0x3B, 0x4B, 0x3E, 0x4F, 0x09,
814*4882a593Smuzhiyun 		0x57, 0x0E, 0x02, 0x00, 0x4F, 0x09, 0xFE, 0x3F, 0xE8, 0x10, 0x00
815*4882a593Smuzhiyun 	}, {
816*4882a593Smuzhiyun 		0x04, 0x00, 0xA7, 0x4F, 0x09, 0xCC, 0x3A, 0x7E, 0x3E, 0x4F, 0x09,
817*4882a593Smuzhiyun 		0x69, 0x0D, 0x0B, 0x00, 0x4F, 0x09, 0xFE, 0x3F, 0x1D, 0x11, 0x00
818*4882a593Smuzhiyun 	}, {
819*4882a593Smuzhiyun 		0x10, 0x10, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820*4882a593Smuzhiyun 		0xe0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x06, 0x10
821*4882a593Smuzhiyun 	}, {
822*4882a593Smuzhiyun 		0xED, 0xED, 0x00, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823*4882a593Smuzhiyun 		0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x09, 0xED
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun };
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun struct it6616_reg_set it6616_hdmi_init_table[] = {
828*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
829*4882a593Smuzhiyun 	{0x22, 0xFF, 0x08},
830*4882a593Smuzhiyun 	{0x22, 0xFF, 0x17},
831*4882a593Smuzhiyun 	{0x23, 0xFF, 0x1F},
832*4882a593Smuzhiyun 	{0x2B, 0xFF, 0x1F},
833*4882a593Smuzhiyun 	{0x24, 0xFF, 0xF8},
834*4882a593Smuzhiyun 	{0x22, 0xFF, 0x10},
835*4882a593Smuzhiyun 	{0x23, 0xFF, 0xA0},
836*4882a593Smuzhiyun 	{0x2B, 0xFF, 0xA0},
837*4882a593Smuzhiyun 	{0x24, 0xFF, 0x00},
838*4882a593Smuzhiyun 	{0x2F, 0xFF, 0xAD},
839*4882a593Smuzhiyun 	{0x34, 0xFF, 0x00},
840*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x03},
841*4882a593Smuzhiyun 	{0xAA, 0xFF, 0xEC},
842*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
843*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x03},
844*4882a593Smuzhiyun 	{0xAC, 0xFF, 0x40},
845*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
846*4882a593Smuzhiyun 	{0x3A, 0xFF, 0x89},
847*4882a593Smuzhiyun 	{0x43, 0xFF, 0x01},
848*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x04},
849*4882a593Smuzhiyun 	{0x43, 0xFF, 0x01},
850*4882a593Smuzhiyun 	{0x3A, 0xFF, 0x89},
851*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x03},
852*4882a593Smuzhiyun 	{0xA8, 0xFF, 0x0B},
853*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
854*4882a593Smuzhiyun 	{0x4F, 0xFF, 0x84},
855*4882a593Smuzhiyun 	{0x44, 0xFF, 0x19},
856*4882a593Smuzhiyun 	{0x46, 0xFF, 0x15},
857*4882a593Smuzhiyun 	{0x47, 0xFF, 0x88},
858*4882a593Smuzhiyun 	{0xD9, 0xFF, 0x00},
859*4882a593Smuzhiyun 	{0xF0, 0xFF, 0x78},
860*4882a593Smuzhiyun 	{0xF1, 0xFF, 0x10},
861*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x03},
862*4882a593Smuzhiyun 	{0x3A, 0xFF, 0x02},
863*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
864*4882a593Smuzhiyun 	{0x28, 0xFF, 0x88},
865*4882a593Smuzhiyun 	{0x6E, 0xFF, 0x00},
866*4882a593Smuzhiyun 	{0x77, 0xFF, 0x87},
867*4882a593Smuzhiyun 	{0x7B, 0xFF, 0x00},
868*4882a593Smuzhiyun 	{0x86, 0xFF, 0x00},
869*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
870*4882a593Smuzhiyun 	{0x36, 0xFF, 0x06},
871*4882a593Smuzhiyun 	{0x8F, 0xFF, 0x41},
872*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x01},
873*4882a593Smuzhiyun 	{0xC0, 0xFF, 0x42},
874*4882a593Smuzhiyun 	{0xC4, 0x70, 3<<4},
875*4882a593Smuzhiyun 	{0xC4, BIT(7), 0<<7},
876*4882a593Smuzhiyun 	{0xC7, 0xFF, 0x7F},
877*4882a593Smuzhiyun 	{0xC8, 0xFF, 0x1F},
878*4882a593Smuzhiyun 	{0xC9, 0xFF, 0x90},
879*4882a593Smuzhiyun 	{0xCA, 0xFF, 0x99},
880*4882a593Smuzhiyun 	{0x0F, 0xFF, 0x00},
881*4882a593Smuzhiyun 	{0x86, 0x0C, 0x08},
882*4882a593Smuzhiyun 	{0x81, BIT(7), BIT(7)},
883*4882a593Smuzhiyun 	{BANK, BANKM, 0x01},
884*4882a593Smuzhiyun 	{0x10, 0xFF, 0x00},
885*4882a593Smuzhiyun 	{0x11, 0xFF, 0x00},
886*4882a593Smuzhiyun 	{0x12, 0xFF, 0x00},
887*4882a593Smuzhiyun 	{0x13, 0xFF, 0x00},
888*4882a593Smuzhiyun 	{0x28, 0xFF, 0x00},
889*4882a593Smuzhiyun 	{0x29, 0xFF, 0x00},
890*4882a593Smuzhiyun 	{0x2A, 0xFF, 0x00},
891*4882a593Smuzhiyun 	{0x2B, 0xFF, 0x00},
892*4882a593Smuzhiyun 	{0x2C, 0xFF, 0x00},
893*4882a593Smuzhiyun 	{0xC0, 0xC0, 0x40},
894*4882a593Smuzhiyun 	{BANK, BANKM, 0x03},
895*4882a593Smuzhiyun 	{0xE3, 0xFF, 0x07},
896*4882a593Smuzhiyun 	{0x27, 0xFF, DEFAULT_RS_LEVEL},
897*4882a593Smuzhiyun 	{0x28, 0xFF, DEFAULT_RS_LEVEL},
898*4882a593Smuzhiyun 	{0x29, 0xFF, DEFAULT_RS_LEVEL},
899*4882a593Smuzhiyun 	{0xA7, BIT(6), BIT(6)},
900*4882a593Smuzhiyun 	{0x21, BIT(2), BIT(2)},
901*4882a593Smuzhiyun 	{0xF8, 0xFF, 0xC3},
902*4882a593Smuzhiyun 	{0xF8, 0xFF, 0xA5},
903*4882a593Smuzhiyun 	{BANK, BANKM, 0x01},
904*4882a593Smuzhiyun 	{0x5F, 0xFF, 0x04},
905*4882a593Smuzhiyun 	{0x58, 0xFF, 0x12},
906*4882a593Smuzhiyun 	{0x58, 0xFF, 0x02},
907*4882a593Smuzhiyun 	{0x5F, 0xFF, 0x00},
908*4882a593Smuzhiyun 	{BANK, BANKM, 0x00},
909*4882a593Smuzhiyun 	{0xF8, 0xFF, 0xFF},
910*4882a593Smuzhiyun 	{BANK, BANKM, 0x04},
911*4882a593Smuzhiyun 	{0x3C, BIT(5), 0x000},
912*4882a593Smuzhiyun 	{BANK, BANKM, 0x00},
913*4882a593Smuzhiyun 	{0x91, BIT(6), BIT(6)},
914*4882a593Smuzhiyun 	{BANK, BANKM, 0x03},
915*4882a593Smuzhiyun 	{0xF0, 0xFF, 0xC0},
916*4882a593Smuzhiyun 	{BANK, BANKM, 0x00},
917*4882a593Smuzhiyun 	{0x21, BIT(6), BIT(6)},
918*4882a593Smuzhiyun 	{0xCE, 0x30, 0x00},
919*4882a593Smuzhiyun 	{BANK, BANKM, 0x04},
920*4882a593Smuzhiyun 	{0xCE, 0x30, 0x00},
921*4882a593Smuzhiyun 	{0x42, 0xE0, 0xC0},
922*4882a593Smuzhiyun 	{BANK, BANKM, 0x00},
923*4882a593Smuzhiyun 	{0x42, 0xE0, 0xC0},
924*4882a593Smuzhiyun 	{0x7B, BIT(4), BIT(4)},
925*4882a593Smuzhiyun 	{0x3C, 0x21, 0x00},
926*4882a593Smuzhiyun 	{0x3B, 0xFF, 0x23},
927*4882a593Smuzhiyun 	{0xF6, 0xFF, 0x08},
928*4882a593Smuzhiyun 	{BANK, BANKM, 0x04},
929*4882a593Smuzhiyun 	{0x3C, 0x21, 0x00},
930*4882a593Smuzhiyun 	{0x3B, 0xFF, 0x23},
931*4882a593Smuzhiyun 	{BANK, BANKM, 0x00},
932*4882a593Smuzhiyun 	{0x59, 0xFF, 0x00},
933*4882a593Smuzhiyun 	{0xFF, 0xFF, 0xFF},
934*4882a593Smuzhiyun };
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun static struct it6616 *g_it6616;
937*4882a593Smuzhiyun static void it6616_format_change(struct v4l2_subdev *sd);
938*4882a593Smuzhiyun static int it6616_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd);
939*4882a593Smuzhiyun static int it6616_s_dv_timings(struct v4l2_subdev *sd,
940*4882a593Smuzhiyun 				struct v4l2_dv_timings *timings);
941*4882a593Smuzhiyun 
to_it6616(struct v4l2_subdev * sd)942*4882a593Smuzhiyun static inline struct it6616 *to_it6616(struct v4l2_subdev *sd)
943*4882a593Smuzhiyun {
944*4882a593Smuzhiyun 	return container_of(sd, struct it6616, sd);
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun 
it6616_hdmi_read(struct regmap * regmap,u8 reg)947*4882a593Smuzhiyun static u8 it6616_hdmi_read(struct regmap *regmap, u8 reg)
948*4882a593Smuzhiyun {
949*4882a593Smuzhiyun 	unsigned int val;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	regmap_read(regmap, reg, &val);
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	return (u8)val;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
it6616_hdmi_write(struct regmap * regmap,u8 reg,u8 value)956*4882a593Smuzhiyun static int it6616_hdmi_write(struct regmap *regmap, u8 reg, u8 value)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun 	return regmap_write(regmap, reg, value);
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun 
it6616_hdmi_set(struct regmap * regmap,u8 reg,u8 mask,u8 value)961*4882a593Smuzhiyun static int it6616_hdmi_set(struct regmap *regmap, u8 reg, u8 mask, u8 value)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	return regmap_update_bits(regmap, reg, mask, value);
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun 
it6616_mipi_tx_read(struct regmap * regmap,u8 reg)966*4882a593Smuzhiyun static u8 it6616_mipi_tx_read(struct regmap *regmap, u8 reg)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun 	unsigned int val;
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	regmap_read(regmap, reg, &val);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	return (u8)val;
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun 
it6616_mipi_tx_write(struct regmap * regmap,u8 reg,u8 value)975*4882a593Smuzhiyun static int it6616_mipi_tx_write(struct regmap *regmap, u8 reg, u8 value)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun 	return regmap_write(regmap, reg, value);
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun 
it6616_mipi_tx_set_bits(struct regmap * regmap,u8 reg,u8 mask,u8 value)980*4882a593Smuzhiyun static int it6616_mipi_tx_set_bits(struct regmap *regmap, u8 reg, u8 mask, u8 value)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun 	return regmap_update_bits(regmap, reg, mask, value);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun 
it6616_hdmi_edid_read(struct regmap * regmap,u8 * edid,int start,int length)985*4882a593Smuzhiyun static int it6616_hdmi_edid_read(struct regmap *regmap, u8 *edid, int start, int length)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun 	return regmap_bulk_read(regmap, start, edid, length);
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun 
it6616_hdmi_edid_write(struct regmap * regmap,u8 * edid,int start,int length)990*4882a593Smuzhiyun static int it6616_hdmi_edid_write(struct regmap *regmap, u8 *edid, int start, int length)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	return regmap_bulk_write(regmap, start, edid, length);
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun 
it6616_hdmi_chgbank(struct regmap * regmap,u8 bank)995*4882a593Smuzhiyun static void it6616_hdmi_chgbank(struct regmap *regmap, u8 bank)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun 	it6616_hdmi_set(regmap, 0x0F, 0x07, (u8)(bank & 0x07));
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
it6616_hdim_write_table(struct regmap * regmap,struct it6616_reg_set * tdata)1000*4882a593Smuzhiyun static void it6616_hdim_write_table(struct regmap *regmap, struct it6616_reg_set *tdata)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	while (tdata->ucAddr != 0xff) {
1003*4882a593Smuzhiyun 		if (tdata->andmask == 0xff)
1004*4882a593Smuzhiyun 			it6616_hdmi_write(regmap, tdata->ucAddr, tdata->ucValue);
1005*4882a593Smuzhiyun 		else
1006*4882a593Smuzhiyun 			it6616_hdmi_set(regmap, tdata->ucAddr, tdata->andmask, tdata->ucValue);
1007*4882a593Smuzhiyun 		tdata++;
1008*4882a593Smuzhiyun 	}
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun 
it6616_mipi_tx_get_video_stable(struct it6616 * it6616)1011*4882a593Smuzhiyun static bool it6616_mipi_tx_get_video_stable(struct it6616 *it6616)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1014*4882a593Smuzhiyun 	u8 reg09h;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	reg09h = it6616_mipi_tx_read(mipi, 0x09);
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	return !!(reg09h & 0x40);
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun 
it6616_mipitx_init_bus_para(struct it6616 * it6616)1021*4882a593Smuzhiyun static void it6616_mipitx_init_bus_para(struct it6616 *it6616)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun 	struct bus_para *bus_para = &it6616->mipi.bus_para_config;
1024*4882a593Smuzhiyun 	u8 lpx = 0x03, mipi_tx_hs_prepare = 0x01;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	bus_para->swap_pn = MIPI_TX_PN_SWAP;
1027*4882a593Smuzhiyun 	bus_para->swap_lan = MIPI_TX_LANE_SWAP;
1028*4882a593Smuzhiyun 	bus_para->pclk_inv = MIPI_TX_ENABLE_PCLK_INV;
1029*4882a593Smuzhiyun 	bus_para->mclk_inv = MIPI_TX_ENABLE_MCLK_INV;
1030*4882a593Smuzhiyun 	bus_para->lpx_num =
1031*4882a593Smuzhiyun 		it6616->mipi_tx_enable_manual_adjusted_d_phy ? MIPI_TX_LPX : lpx;
1032*4882a593Smuzhiyun 	bus_para->mipi_tx_hs_prepare =
1033*4882a593Smuzhiyun 		it6616->mipi_tx_enable_manual_adjusted_d_phy ?
1034*4882a593Smuzhiyun 		MIPI_TX_HS_PREPARE : mipi_tx_hs_prepare;
1035*4882a593Smuzhiyun 	bus_para->tx_sel_line_start = true;
1036*4882a593Smuzhiyun 	bus_para->tx_bypass = MIPI_TX_ENABLE_BY_PASS;
1037*4882a593Smuzhiyun 	bus_para->tx_enable_hs_pre_1T = MIPI_TX_ENABLE_HS_PRE_1T;
1038*4882a593Smuzhiyun 	bus_para->tx_vlpm_length = MIPI_TX_V_LPM_LENGTH;
1039*4882a593Smuzhiyun 	bus_para->tx_hlpm_length = MIPI_TX_H_LPM_LENGTH;
1040*4882a593Smuzhiyun 	bus_para->tx_enable_h_enter_lpm = MIPI_TX_ENABLE_H_ENTER_LPM;
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun 
it6616_get_dcs_ecc(int dcshead)1043*4882a593Smuzhiyun static int it6616_get_dcs_ecc(int dcshead)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun 	int q0, q1, q2, q3, q4, q5;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	q0 = ((dcshead >> 0) & (0x01)) ^ ((dcshead >> 1) & (0x01)) ^
1048*4882a593Smuzhiyun 		((dcshead >> 2) & (0x01)) ^ ((dcshead >> 4) & (0x01)) ^
1049*4882a593Smuzhiyun 		((dcshead >> 5) & (0x01)) ^ ((dcshead >> 7) & (0x01)) ^
1050*4882a593Smuzhiyun 		((dcshead >> 10) & (0x01)) ^ ((dcshead >> 11) & (0x01)) ^
1051*4882a593Smuzhiyun 		((dcshead >> 13) & (0x01)) ^ ((dcshead >> 16) & (0x01)) ^
1052*4882a593Smuzhiyun 		((dcshead >> 20) & (0x01)) ^ ((dcshead >> 21) & (0x01)) ^
1053*4882a593Smuzhiyun 		((dcshead >> 22) & (0x01)) ^ ((dcshead >> 23) & (0x01));
1054*4882a593Smuzhiyun 	q1 = ((dcshead >> 0) & (0x01)) ^ ((dcshead >> 1) & (0x01)) ^
1055*4882a593Smuzhiyun 		((dcshead >> 3) & (0x01)) ^ ((dcshead >> 4) & (0x01)) ^
1056*4882a593Smuzhiyun 		((dcshead >> 6) & (0x01)) ^ ((dcshead >> 8) & (0x01)) ^
1057*4882a593Smuzhiyun 		((dcshead >> 10) & (0x01)) ^ ((dcshead >> 12) & (0x01)) ^
1058*4882a593Smuzhiyun 		((dcshead >> 14) & (0x01)) ^ ((dcshead >> 17) & (0x01)) ^
1059*4882a593Smuzhiyun 		((dcshead >> 20) & (0x01)) ^ ((dcshead >> 21) & (0x01)) ^
1060*4882a593Smuzhiyun 		((dcshead >> 22) & (0x01)) ^ ((dcshead >> 23) & (0x01));
1061*4882a593Smuzhiyun 	q2 = ((dcshead >> 0) & (0x01)) ^ ((dcshead >> 2) & (0x01)) ^
1062*4882a593Smuzhiyun 		((dcshead >> 3) & (0x01)) ^ ((dcshead >> 5) & (0x01)) ^
1063*4882a593Smuzhiyun 		((dcshead >> 6) & (0x01)) ^ ((dcshead >> 9) & (0x01)) ^
1064*4882a593Smuzhiyun 		((dcshead >> 11) & (0x01)) ^ ((dcshead >> 12) & (0x01)) ^
1065*4882a593Smuzhiyun 		((dcshead >> 15) & (0x01)) ^ ((dcshead >> 18) & (0x01)) ^
1066*4882a593Smuzhiyun 		((dcshead >> 20) & (0x01)) ^ ((dcshead >> 21) & (0x01)) ^
1067*4882a593Smuzhiyun 		((dcshead >> 22) & (0x01));
1068*4882a593Smuzhiyun 	q3 = ((dcshead >> 1) & (0x01)) ^ ((dcshead >> 2) & (0x01)) ^
1069*4882a593Smuzhiyun 		((dcshead >> 3) & (0x01)) ^ ((dcshead >> 7) & (0x01)) ^
1070*4882a593Smuzhiyun 		((dcshead >> 8) & (0x01)) ^ ((dcshead >> 9) & (0x01)) ^
1071*4882a593Smuzhiyun 		((dcshead >> 13) & (0x01)) ^ ((dcshead >> 14) & (0x01)) ^
1072*4882a593Smuzhiyun 		((dcshead >> 15) & (0x01)) ^ ((dcshead >> 19) & (0x01)) ^
1073*4882a593Smuzhiyun 		((dcshead >> 20) & (0x01)) ^ ((dcshead >> 21) & (0x01)) ^
1074*4882a593Smuzhiyun 		((dcshead >> 23) & (0x01));
1075*4882a593Smuzhiyun 	q4 = ((dcshead >> 4) & (0x01)) ^ ((dcshead >> 5) & (0x01)) ^
1076*4882a593Smuzhiyun 		((dcshead >> 6) & (0x01)) ^ ((dcshead >> 7) & (0x01)) ^
1077*4882a593Smuzhiyun 		((dcshead >> 8) & (0x01)) ^ ((dcshead >> 9) & (0x01)) ^
1078*4882a593Smuzhiyun 		((dcshead >> 16) & (0x01)) ^ ((dcshead >> 17) & (0x01)) ^
1079*4882a593Smuzhiyun 		((dcshead >> 18) & (0x01)) ^ ((dcshead >> 19) & (0x01)) ^
1080*4882a593Smuzhiyun 		((dcshead >> 20) & (0x01)) ^ ((dcshead >> 22) & (0x01)) ^
1081*4882a593Smuzhiyun 		((dcshead >> 23) & (0x01));
1082*4882a593Smuzhiyun 	q5 = ((dcshead >> 10) & (0x01)) ^ ((dcshead >> 11) & (0x01)) ^
1083*4882a593Smuzhiyun 		((dcshead >> 12) & (0x01)) ^ ((dcshead >> 13) & (0x01)) ^
1084*4882a593Smuzhiyun 		((dcshead >> 14) & (0x01)) ^ ((dcshead >> 15) & (0x01)) ^
1085*4882a593Smuzhiyun 		((dcshead >> 16) & (0x01)) ^ ((dcshead >> 17) & (0x01)) ^
1086*4882a593Smuzhiyun 		((dcshead >> 18) & (0x01)) ^ ((dcshead >> 19) & (0x01)) ^
1087*4882a593Smuzhiyun 		((dcshead >> 21) & (0x01)) ^ ((dcshead >> 22) & (0x01)) ^
1088*4882a593Smuzhiyun 		((dcshead >> 23) & (0x01));
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	return (q0 + (q1 << 1) + (q2 << 2) + (q3 << 3) + (q4 << 4) + (q5 << 5));
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun 
it6616_dcs_crc8t(int crcq16b,const u8 crc8bin)1093*4882a593Smuzhiyun static int it6616_dcs_crc8t(int crcq16b, const u8 crc8bin)
1094*4882a593Smuzhiyun {
1095*4882a593Smuzhiyun 	int lfsrout = 0, lfsr[16], i;
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	lfsr[15] = ((crc8bin >> 7) & 0x01) ^ ((crc8bin >> 3) & 0x01) ^
1098*4882a593Smuzhiyun 		   ((crcq16b >> 7) & 0x01) ^ ((crcq16b >> 3) & 0x01);
1099*4882a593Smuzhiyun 	lfsr[14] = ((crc8bin >> 6) & 0x01) ^ ((crc8bin >> 2) & 0x01) ^
1100*4882a593Smuzhiyun 		   ((crcq16b >> 6) & 0x01) ^ ((crcq16b >> 2) & 0x01);
1101*4882a593Smuzhiyun 	lfsr[13] = ((crc8bin >> 5) & 0x01) ^ ((crc8bin >> 1) & 0x01) ^
1102*4882a593Smuzhiyun 		   ((crcq16b >> 5) & 0x01) ^ ((crcq16b >> 1) & 0x01);
1103*4882a593Smuzhiyun 	lfsr[12] = ((crc8bin >> 4) & 0x01) ^ ((crc8bin >> 0) & 0x01) ^
1104*4882a593Smuzhiyun 		   ((crcq16b >> 4) & 0x01) ^ ((crcq16b >> 0) & 0x01);
1105*4882a593Smuzhiyun 	lfsr[11] = ((crc8bin >> 3) & 0x01) ^ ((crcq16b >> 3) & 0x01);
1106*4882a593Smuzhiyun 	lfsr[10] = ((crc8bin >> 7) & 0x01) ^ ((crc8bin >> 3) & 0x01) ^
1107*4882a593Smuzhiyun 		   ((crc8bin >> 2) & 0x01) ^ ((crcq16b >> 7) & 0x01) ^
1108*4882a593Smuzhiyun 		   ((crcq16b >> 3) & 0x01) ^ ((crcq16b >> 2) & 0x01);
1109*4882a593Smuzhiyun 	lfsr[9] = ((crc8bin >> 6) & 0x01) ^ ((crc8bin >> 2) & 0x01) ^
1110*4882a593Smuzhiyun 		  ((crc8bin >> 1) & 0x01) ^ ((crcq16b >> 6) & 0x01) ^
1111*4882a593Smuzhiyun 		  ((crcq16b >> 2) & 0x01) ^ ((crcq16b >> 1) & 0x01);
1112*4882a593Smuzhiyun 	lfsr[8] = ((crc8bin >> 5) & 0x01) ^ ((crc8bin >> 1) & 0x01) ^
1113*4882a593Smuzhiyun 		  ((crc8bin >> 0) & 0x01) ^ ((crcq16b >> 5) & 0x01) ^
1114*4882a593Smuzhiyun 		  ((crcq16b >> 1) & 0x01) ^ ((crcq16b >> 0) & 0x01);
1115*4882a593Smuzhiyun 	lfsr[7] = ((crc8bin >> 4) & 0x01) ^ ((crc8bin >> 0) & 0x01) ^
1116*4882a593Smuzhiyun 		  ((crcq16b >> 15) & 0x01) ^ ((crcq16b >> 4) & 0x01) ^
1117*4882a593Smuzhiyun 		  ((crcq16b >> 0) & 0x01);
1118*4882a593Smuzhiyun 	lfsr[6] = ((crc8bin >> 3) & 0x01) ^
1119*4882a593Smuzhiyun 		  ((crcq16b >> 14) & 0x01) ^ ((crcq16b >> 3) & 0x01);
1120*4882a593Smuzhiyun 	lfsr[5] = ((crc8bin >> 2) & 0x01) ^
1121*4882a593Smuzhiyun 		  ((crcq16b >> 13) & 0x01) ^ ((crcq16b >> 2) & 0x01);
1122*4882a593Smuzhiyun 	lfsr[4] = ((crc8bin >> 1) & 0x01) ^
1123*4882a593Smuzhiyun 		  ((crcq16b >> 12) & 0x01) ^ ((crcq16b >> 1) & 0x01);
1124*4882a593Smuzhiyun 	lfsr[3] = ((crc8bin >> 7) & 0x01) ^ ((crc8bin >> 3) & 0x01) ^
1125*4882a593Smuzhiyun 		  ((crc8bin >> 0) & 0x01) ^ ((crcq16b >> 11) & 0x01) ^
1126*4882a593Smuzhiyun 		  ((crcq16b >> 7) & 0x01) ^ ((crcq16b >> 3) & 0x01) ^
1127*4882a593Smuzhiyun 		  ((crcq16b >> 0) & 0x01);
1128*4882a593Smuzhiyun 	lfsr[2] = ((crc8bin >> 6) & 0x01) ^ ((crc8bin >> 2) & 0x01) ^
1129*4882a593Smuzhiyun 		  ((crcq16b >> 10) & 0x01) ^ ((crcq16b >> 6) & 0x01) ^
1130*4882a593Smuzhiyun 		  ((crcq16b >> 2) & 0x01);
1131*4882a593Smuzhiyun 	lfsr[1] = ((crc8bin >> 5) & 0x01) ^ ((crc8bin >> 1) & 0x01) ^
1132*4882a593Smuzhiyun 		  ((crcq16b >> 9) & 0x01) ^ ((crcq16b >> 5) & 0x01) ^
1133*4882a593Smuzhiyun 		  ((crcq16b >> 1) & 0x01);
1134*4882a593Smuzhiyun 	lfsr[0] = ((crc8bin >> 4) & 0x01) ^ ((crc8bin >> 0) & 0x01) ^
1135*4882a593Smuzhiyun 		  ((crcq16b >> 8) & 0x01) ^ ((crcq16b >> 4) & 0x01) ^
1136*4882a593Smuzhiyun 		  ((crcq16b >> 0) & 0x01);
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(lfsr); i++)
1139*4882a593Smuzhiyun 		lfsrout = lfsrout + (lfsr[i] << i);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	return lfsrout;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun 
it6616_get_dcs_crc(int bytenum,const u8 * crcbyte)1144*4882a593Smuzhiyun static int it6616_get_dcs_crc(int bytenum, const u8 *crcbyte)
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun 	int i, crctemp = 0xFFFF;
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 	for (i = 0; i <= bytenum - 1; i++)
1149*4882a593Smuzhiyun 		crctemp = it6616_dcs_crc8t(crctemp, crcbyte[i]);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	return crctemp;
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun 
it6616_mipi_tx_setup_long_packet_header(struct mipi_packet * pheader,u32 word_count)1154*4882a593Smuzhiyun static void it6616_mipi_tx_setup_long_packet_header(struct mipi_packet *pheader,
1155*4882a593Smuzhiyun 						u32 word_count)
1156*4882a593Smuzhiyun {
1157*4882a593Smuzhiyun 	int header;
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 	pheader->word_count_h = word_count >> 8;
1160*4882a593Smuzhiyun 	pheader->word_count_l = (u8)word_count;
1161*4882a593Smuzhiyun 	header = pheader->data_id | pheader->word_count_h << 16 | pheader->word_count_l << 8;
1162*4882a593Smuzhiyun 	pheader->ecc = it6616_get_dcs_ecc(header);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun 
it6616_mipi_tx_get_packet_size(struct it6616 * it6616,const struct dcs_setting_entry * dcs_setting_table,enum dcs_cmd_name cmd_name)1165*4882a593Smuzhiyun static enum mipi_packet_size it6616_mipi_tx_get_packet_size(struct it6616 *it6616,
1166*4882a593Smuzhiyun 					const struct dcs_setting_entry *dcs_setting_table,
1167*4882a593Smuzhiyun 					enum dcs_cmd_name cmd_name)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1170*4882a593Smuzhiyun 	u8 i, size = ARRAY_SIZE(packet_size_data_id_map);
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	for (i = 0; i < size; i++) {
1173*4882a593Smuzhiyun 		if (dcs_setting_table[cmd_name].data_id == packet_size_data_id_map[i].data_id)
1174*4882a593Smuzhiyun 			break;
1175*4882a593Smuzhiyun 	}
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	if (i == size) {
1178*4882a593Smuzhiyun 		if (dcs_setting_table[cmd_name].count == 0) {
1179*4882a593Smuzhiyun 			dev_err(dev, "error! cmd index: %d count = 0", cmd_name);
1180*4882a593Smuzhiyun 			return UNKNOWN_PACKET;
1181*4882a593Smuzhiyun 		} else if (dcs_setting_table[cmd_name].count < 3) {
1182*4882a593Smuzhiyun 			return SHORT_PACKET;
1183*4882a593Smuzhiyun 		} else {
1184*4882a593Smuzhiyun 			return LONG_PACKET;
1185*4882a593Smuzhiyun 		}
1186*4882a593Smuzhiyun 	}
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	return packet_size_data_id_map[i].packet_size;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun 
it6616_mipi_tx_get_packet_fire_state(struct it6616 * it6616)1191*4882a593Smuzhiyun static void it6616_mipi_tx_get_packet_fire_state(struct it6616 *it6616)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1194*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1195*4882a593Smuzhiyun 	int lp_cmd_fifo, link_data_fifo;
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	lp_cmd_fifo = it6616_mipi_tx_read(mipi, 0x71) & 0x0F;
1198*4882a593Smuzhiyun 	link_data_fifo = it6616_mipi_tx_read(mipi, 0x72);
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	if (lp_cmd_fifo != 0)
1201*4882a593Smuzhiyun 		dev_err(dev,
1202*4882a593Smuzhiyun 			"error! fire low power cmd fail, remain bytes not fire, reg0x71:0x%02x",
1203*4882a593Smuzhiyun 			lp_cmd_fifo);
1204*4882a593Smuzhiyun 	if (link_data_fifo != 0)
1205*4882a593Smuzhiyun 		dev_err(dev,
1206*4882a593Smuzhiyun 			"error! fire link0 low power data fail, remain %d bytes not fire, reg0x72:0x%02x",
1207*4882a593Smuzhiyun 			link_data_fifo, link_data_fifo);
1208*4882a593Smuzhiyun }
1209*4882a593Smuzhiyun 
it6616_mipi_tx_setup_packet(struct it6616 * it6616,struct mipi_packet * pheader,const struct dcs_setting_entry * dcs_setting_table,enum dcs_cmd_name cmd_name)1210*4882a593Smuzhiyun static void it6616_mipi_tx_setup_packet(struct it6616 *it6616, struct mipi_packet *pheader,
1211*4882a593Smuzhiyun 			  const struct dcs_setting_entry *dcs_setting_table,
1212*4882a593Smuzhiyun 			  enum dcs_cmd_name cmd_name)
1213*4882a593Smuzhiyun {
1214*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1215*4882a593Smuzhiyun 	int short_cmd;
1216*4882a593Smuzhiyun 	enum mipi_packet_size packet_size;
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	pheader->data_id = dcs_setting_table[cmd_name].data_id;
1219*4882a593Smuzhiyun 	packet_size = it6616_mipi_tx_get_packet_size(it6616, dcs_setting_table, cmd_name);
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	if (packet_size == UNKNOWN_PACKET) {
1222*4882a593Smuzhiyun 		dev_err(dev, "error! unknown packet size and check dcs table parameter");
1223*4882a593Smuzhiyun 		return;
1224*4882a593Smuzhiyun 	}
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	if (packet_size == SHORT_PACKET) {
1227*4882a593Smuzhiyun 		pheader->word_count_l = dcs_setting_table[cmd_name].para_list[0];
1228*4882a593Smuzhiyun 		pheader->word_count_h = dcs_setting_table[cmd_name].para_list[1];
1229*4882a593Smuzhiyun 		short_cmd = pheader->data_id | pheader->word_count_l << 8 |
1230*4882a593Smuzhiyun 			pheader->word_count_h << 16;
1231*4882a593Smuzhiyun 		pheader->ecc = it6616_get_dcs_ecc(short_cmd);
1232*4882a593Smuzhiyun 	}
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	if (packet_size == LONG_PACKET)
1235*4882a593Smuzhiyun 		it6616_mipi_tx_setup_long_packet_header(pheader, dcs_setting_table[cmd_name].count);
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun 
it6616_mipi_tx_fire_packet(struct it6616 * it6616,const struct dcs_setting_entry * dcs_setting_table,enum dcs_cmd_name cmd_name)1238*4882a593Smuzhiyun static inline void it6616_mipi_tx_fire_packet(struct it6616 *it6616,
1239*4882a593Smuzhiyun 			const struct dcs_setting_entry *dcs_setting_table,
1240*4882a593Smuzhiyun 			enum dcs_cmd_name cmd_name)
1241*4882a593Smuzhiyun {
1242*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x75, dcs_setting_table[cmd_name].cmd);
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
it6616_mipi_tx_setup_packet_process(struct it6616 * it6616,const struct dcs_setting_entry * dcs_setting_table,enum dcs_cmd_name cmd_name,enum mipi_tx_lp_cmd_header header_select)1247*4882a593Smuzhiyun static void it6616_mipi_tx_setup_packet_process(struct it6616 *it6616,
1248*4882a593Smuzhiyun 			const struct dcs_setting_entry *dcs_setting_table,
1249*4882a593Smuzhiyun 			enum dcs_cmd_name cmd_name,
1250*4882a593Smuzhiyun 			enum mipi_tx_lp_cmd_header header_select)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1253*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1254*4882a593Smuzhiyun 	struct v4l2_subdev *sd = &it6616->sd;
1255*4882a593Smuzhiyun 	struct mipi_packet packet;
1256*4882a593Smuzhiyun 	enum mipi_packet_size packet_size;
1257*4882a593Smuzhiyun 	u32 long_packet_checksum;
1258*4882a593Smuzhiyun 	int i, header_crc, data_count;
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	if (!header_select) {
1261*4882a593Smuzhiyun 		dev_err(dev, "no header packet");
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 		for (i = 0; i < dcs_setting_table[cmd_name].count; i++) {
1264*4882a593Smuzhiyun 			it6616_mipi_tx_write(mipi, 0x73, dcs_setting_table[cmd_name].para_list[i]);
1265*4882a593Smuzhiyun 			v4l2_dbg(1, debug, sd, "data[%d]: 0x%02x ", i,
1266*4882a593Smuzhiyun 					dcs_setting_table[cmd_name].para_list[i]);
1267*4882a593Smuzhiyun 		}
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 		header_crc = 0;
1270*4882a593Smuzhiyun 		goto short_packet;
1271*4882a593Smuzhiyun 	}
1272*4882a593Smuzhiyun 	it6616_mipi_tx_setup_packet(it6616, &packet, dcs_setting_table, cmd_name);
1273*4882a593Smuzhiyun 	packet_size = it6616_mipi_tx_get_packet_size(it6616, dcs_setting_table, cmd_name);
1274*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s packet\n\r", packet_size == LONG_PACKET ? "long" : "short");
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	for (i = 0; i < sizeof(packet); i++) {
1277*4882a593Smuzhiyun 		it6616_mipi_tx_write(mipi, 0x73, ((u8 *)(&packet))[i]);
1278*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "data[%d]: 0x%02x ", i, ((u8 *)(&packet))[i]);
1279*4882a593Smuzhiyun 		msleep(20);
1280*4882a593Smuzhiyun 	}
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	if (packet_size == SHORT_PACKET) {
1283*4882a593Smuzhiyun 		header_crc = 2;
1284*4882a593Smuzhiyun 		goto short_packet;
1285*4882a593Smuzhiyun 	}
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	header_crc = sizeof(packet) + 2;
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	long_packet_checksum = it6616_get_dcs_crc(dcs_setting_table[cmd_name].count,
1290*4882a593Smuzhiyun 					dcs_setting_table[cmd_name].para_list);
1291*4882a593Smuzhiyun 	for (i = 0; i < dcs_setting_table[cmd_name].count; i++) {
1292*4882a593Smuzhiyun 		it6616_mipi_tx_write(mipi, 0x73, dcs_setting_table[cmd_name].para_list[i]);
1293*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd,
1294*4882a593Smuzhiyun 			"cmd para: 0x%02x", dcs_setting_table[cmd_name].para_list[i]);
1295*4882a593Smuzhiyun 	}
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x73, (u8)long_packet_checksum);
1298*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x73, (u8)(long_packet_checksum >> 8));
1299*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd,
1300*4882a593Smuzhiyun 		"long_packet_checksum_l: 0x%02x long_packet_checksum_h: 0x%02x",
1301*4882a593Smuzhiyun 		(u8)long_packet_checksum, (u8)(long_packet_checksum >> 8));
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun short_packet:
1304*4882a593Smuzhiyun 	data_count = dcs_setting_table[cmd_name].count + header_crc;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	if (data_count == LP_CMD_FIFO_SIZE)
1307*4882a593Smuzhiyun 		data_count = 1;
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x74, (it6616->mipi_tx_enable_h_fire_packet << 7) | data_count);
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun 
it6616_mipi_tx_write_lp_cmds(struct it6616 * it6616,const struct dcs_setting_entry * dcs_setting_table,int dcs_table_size,enum dcs_cmd_name start,int count,enum mipi_tx_lp_cmd_header header_select)1312*4882a593Smuzhiyun static void it6616_mipi_tx_write_lp_cmds(struct it6616 *it6616,
1313*4882a593Smuzhiyun 			const struct dcs_setting_entry *dcs_setting_table,
1314*4882a593Smuzhiyun 			int dcs_table_size, enum dcs_cmd_name start,
1315*4882a593Smuzhiyun 			int count, enum mipi_tx_lp_cmd_header header_select)
1316*4882a593Smuzhiyun {
1317*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1318*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1319*4882a593Smuzhiyun 	u8 header_size, i, data_count;
1320*4882a593Smuzhiyun 	u8 enable_force_lp_mode = !it6616_mipi_tx_get_video_stable(it6616);
1321*4882a593Smuzhiyun 	u8 lp_cmd_fifo_size[] = { LP_CMD_FIFO_SIZE };
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x70, 0x03, 0x03);
1324*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x70, 0x03, 0x00);
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	if (enable_force_lp_mode) {
1327*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x05, 0x16, 0x16);
1328*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x05, 0x16, 0x10);
1329*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x04);
1330*4882a593Smuzhiyun 	}
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x3D, 0x00);
1333*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x3E, enable_force_lp_mode ? 0x00 : 0x10);
1334*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x3F, enable_force_lp_mode ? 0x30 : 0x90);
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 	for (i = start; i < start + count; i++) {
1337*4882a593Smuzhiyun 		dev_dbg(dev, "cmd:%d tx reg09:0x%02x", i, it6616_mipi_tx_read(mipi, 0x09));
1338*4882a593Smuzhiyun 		if (i >= dcs_table_size)
1339*4882a593Smuzhiyun 			goto complete_write_dcs;
1340*4882a593Smuzhiyun 		if (dcs_setting_table[i].cmd_name == DELAY) {
1341*4882a593Smuzhiyun 			msleep(dcs_setting_table[i].cmd);
1342*4882a593Smuzhiyun 			continue;
1343*4882a593Smuzhiyun 		}
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 		header_size = header_select ?
1346*4882a593Smuzhiyun 			((it6616_mipi_tx_get_packet_size(it6616, dcs_setting_table, i) ==
1347*4882a593Smuzhiyun 			SHORT_PACKET) ? 2 : 6) : 0;
1348*4882a593Smuzhiyun 		data_count = dcs_setting_table[i].count + header_size;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 		if (data_count > lp_cmd_fifo_size[0]) {
1351*4882a593Smuzhiyun 			dev_err(dev, "error! lp cmd: %d, exceed cmd fifo", i);
1352*4882a593Smuzhiyun 			continue;
1353*4882a593Smuzhiyun 		}
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 		it6616_mipi_tx_setup_packet_process(it6616, dcs_setting_table, i, header_select);
1356*4882a593Smuzhiyun 		it6616_mipi_tx_fire_packet(it6616, dcs_setting_table, i);
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 		if (enable_force_lp_mode)
1359*4882a593Smuzhiyun 			it6616_mipi_tx_get_packet_fire_state(it6616);
1360*4882a593Smuzhiyun 	}
1361*4882a593Smuzhiyun 	msleep(20);
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun complete_write_dcs:
1364*4882a593Smuzhiyun 	if (i >= dcs_table_size && (start + count > dcs_table_size))
1365*4882a593Smuzhiyun 		dev_err(dev, "error! exceed maximum dcs setting table index");
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	if (enable_force_lp_mode) {
1368*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x00);
1369*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x05, 0x16, 0x00);
1370*4882a593Smuzhiyun 	}
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	msleep(20);
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	if (!enable_force_lp_mode)
1375*4882a593Smuzhiyun 		it6616_mipi_tx_get_packet_fire_state(it6616);
1376*4882a593Smuzhiyun }
1377*4882a593Smuzhiyun 
it6616_enter_bus_turn_around(struct it6616 * it6616)1378*4882a593Smuzhiyun static void it6616_enter_bus_turn_around(struct it6616 *it6616)
1379*4882a593Smuzhiyun {
1380*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1381*4882a593Smuzhiyun 	u8 enable_force_lp_mode = !it6616_mipi_tx_get_video_stable(it6616);
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	if (enable_force_lp_mode)
1384*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x04);
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x3E, 0x10);
1387*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x3F, 0x90);
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x74, it6616->mipi_tx_enable_h_fire_packet << 7);
1390*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x75, LP_CMD_BTA);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (enable_force_lp_mode)
1393*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x00);
1394*4882a593Smuzhiyun }
1395*4882a593Smuzhiyun 
it6616_mipi_read_panel(struct it6616 * it6616,const struct dcs_setting_entry * dcs_setting_table,int dcs_table_size,enum dcs_cmd_name cmd_name,u8 * buffer)1396*4882a593Smuzhiyun static __maybe_unused void it6616_mipi_read_panel(struct it6616 *it6616,
1397*4882a593Smuzhiyun 		const struct dcs_setting_entry *dcs_setting_table,
1398*4882a593Smuzhiyun 		int dcs_table_size, enum dcs_cmd_name cmd_name, u8 *buffer)
1399*4882a593Smuzhiyun {
1400*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1401*4882a593Smuzhiyun 	int link0_data_count, i;
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 	it6616_mipi_tx_write_lp_cmds(it6616, dcs_setting_table,
1404*4882a593Smuzhiyun 			dcs_table_size, cmd_name, 1, CALC_HEADER);
1405*4882a593Smuzhiyun 	it6616_enter_bus_turn_around(it6616);
1406*4882a593Smuzhiyun 	msleep(20);
1407*4882a593Smuzhiyun 	link0_data_count = it6616_mipi_tx_read(mipi, 0x7A);
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	for (i = 0; i < link0_data_count; i++)
1410*4882a593Smuzhiyun 		buffer[i] = it6616_mipi_tx_read(mipi, 0x79);
1411*4882a593Smuzhiyun }
1412*4882a593Smuzhiyun 
it6616_mipitx_get_bus_config(struct it6616 * it6616)1413*4882a593Smuzhiyun static int it6616_mipitx_get_bus_config(struct it6616 *it6616)
1414*4882a593Smuzhiyun {
1415*4882a593Smuzhiyun 	struct mipi_bus *bus = &it6616->mipi;
1416*4882a593Smuzhiyun 	const struct bus_config *bus_config_table;
1417*4882a593Smuzhiyun 	struct bus_config *cfg = &bus->bus_para_config.cfg;
1418*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1419*4882a593Smuzhiyun 	int i;
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	bus_config_table = (bus->bus_type == MIPI_CSI) ?
1422*4882a593Smuzhiyun 			it6616_csi_bus_cfg : it6616_dsi_bus_cfg;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	for (i = 0; bus_config_table[i].lane; i++) {
1425*4882a593Smuzhiyun 		if (bus_config_table[i].lane == bus->lane_cnt &&
1426*4882a593Smuzhiyun 			bus_config_table[i].type == bus->data_type) {
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 			bus->bus_para_config.cfg = bus_config_table[i];
1429*4882a593Smuzhiyun 			dev_dbg(dev, "mipi_get_bus_config = %d (%s)",
1430*4882a593Smuzhiyun 				i, (bus->bus_type == MIPI_CSI) ? "MIPI_CSI" : "MIPI_DSI");
1431*4882a593Smuzhiyun 			dev_dbg(dev, "{%X, %X, %X, %X, %X ,%X}",
1432*4882a593Smuzhiyun 				cfg->lane,
1433*4882a593Smuzhiyun 				cfg->type,
1434*4882a593Smuzhiyun 				cfg->reg23_p2m,
1435*4882a593Smuzhiyun 				cfg->regb0_div[0],
1436*4882a593Smuzhiyun 				cfg->regb0_div[1],
1437*4882a593Smuzhiyun 				cfg->regb0_div[2]);
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 			return 0;
1440*4882a593Smuzhiyun 		}
1441*4882a593Smuzhiyun 	}
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun 	dev_err(dev, "mipi_get_bus_config error");
1444*4882a593Smuzhiyun 	return -EINVAL;
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun 
it6616_mipitx_setup_dsi(struct it6616 * it6616)1447*4882a593Smuzhiyun static void it6616_mipitx_setup_dsi(struct it6616 *it6616)
1448*4882a593Smuzhiyun {
1449*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1450*4882a593Smuzhiyun 	struct bus_para *bus = &it6616->mipi.bus_para_config;
1451*4882a593Smuzhiyun 	struct bus_config *cfg = &bus->cfg;
1452*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1453*4882a593Smuzhiyun 	u8 mp_lane_num = cfg->lane - 1;
1454*4882a593Smuzhiyun 	u8 p2m_time_mul = 0x03;
1455*4882a593Smuzhiyun 	u8 p2m_time_div = 0x02;
1456*4882a593Smuzhiyun 	u32 mp_hs_pretime = 0x4a;
1457*4882a593Smuzhiyun 	u32 mp_hs_endtime = 0x09;
1458*4882a593Smuzhiyun 	u8 mp_vid_type = cfg->type;
1459*4882a593Smuzhiyun 	u32 mclk_ps = it6616->tx_mclk_ps, tx_mclk_mhz = it6616->tx_mclk / 1000;
1460*4882a593Smuzhiyun 	u32 mipi_tx_calc_hs_end_time = (6 * mclk_ps - 20 * 1000) / mclk_ps;
1461*4882a593Smuzhiyun 	u8 reg23;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	reg23 = cfg->reg23_p2m;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	p2m_time_mul = reg23 & 0x0F;
1466*4882a593Smuzhiyun 	p2m_time_div = (reg23 & 0xF0) >> 4;
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x28, 0x20, bus->tx_sel_line_start << 5);
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	if (!it6616->mipi_tx_enable_manual_adjusted_d_phy) {
1471*4882a593Smuzhiyun 		if (mp_lane_num == 3) {
1472*4882a593Smuzhiyun 			mp_hs_pretime = (((145 + ((4 + bus->lpx_num) * 20)) * 1000 -
1473*4882a593Smuzhiyun 					((3 * mclk_ps) >> 1)) / mclk_ps);
1474*4882a593Smuzhiyun 			mp_hs_endtime = mipi_tx_calc_hs_end_time + 9;
1475*4882a593Smuzhiyun 		} else if (mp_lane_num == 1) {
1476*4882a593Smuzhiyun 			mp_hs_pretime = ((((145 + ((4 + bus->lpx_num) * 20)) * 1000 -
1477*4882a593Smuzhiyun 					((3 * mclk_ps) >> 1)) / mclk_ps) >> 1);
1478*4882a593Smuzhiyun 			mp_hs_endtime = (mipi_tx_calc_hs_end_time >> 1) + 9;
1479*4882a593Smuzhiyun 		} else {
1480*4882a593Smuzhiyun 			mp_hs_pretime = ((((145 + ((4 + bus->lpx_num) * 20)) * 1000 -
1481*4882a593Smuzhiyun 					((3 * mclk_ps) >> 1)) / mclk_ps) >> 2);
1482*4882a593Smuzhiyun 			mp_hs_endtime = (mipi_tx_calc_hs_end_time >> 2) + 9;
1483*4882a593Smuzhiyun 		}
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun 		if (mipi_tx_calc_hs_end_time <= 0)
1486*4882a593Smuzhiyun 			mp_hs_endtime = 3;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 		if (tx_mclk_mhz >= 300)
1489*4882a593Smuzhiyun 			mp_hs_pretime += 20;
1490*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 250)
1491*4882a593Smuzhiyun 			mp_hs_pretime += 18;
1492*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 200)
1493*4882a593Smuzhiyun 			mp_hs_pretime += 15;
1494*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 150)
1495*4882a593Smuzhiyun 			mp_hs_pretime += 12;
1496*4882a593Smuzhiyun 		else
1497*4882a593Smuzhiyun 			mp_hs_pretime += 9;
1498*4882a593Smuzhiyun 	} else {
1499*4882a593Smuzhiyun 		mp_hs_pretime = MIPI_TX_HS_PREPARE_ZERO;
1500*4882a593Smuzhiyun 		mp_hs_endtime = MIPI_TX_HS_TRAIL;
1501*4882a593Smuzhiyun 	}
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	//dsi setting
1504*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5e, 0x03, (bus->tx_vlpm_length >> 8) & 0x03);
1505*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5d, 0xff, bus->tx_vlpm_length & 0xFF);
1506*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5e, 0x0c, (bus->tx_hlpm_length & 0x300) >> 6);
1507*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5f, 0xff, bus->tx_hlpm_length & 0xFF);
1508*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5e, 0x10, bus->tx_enable_h_enter_lpm << 4);
1509*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x6a, 0xff, bus->p2m_delay.tx_dsi_vsync_delay);
1510*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x6c, 0xff, mp_hs_pretime);
1511*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x6d, 0xff, mp_hs_endtime);
1512*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5c, 0x03, (MIPI_TX_ENABLE_DSI_EOTP_PACKET << 1) |
1513*4882a593Smuzhiyun 			MIPI_TX_ENABLE_DSI_SYNC_EVENT);
1514*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x5c, 0xf0, ((mp_vid_type & 0x30) << 2) |
1515*4882a593Smuzhiyun 			((mp_vid_type & 0x3) << 4));
1516*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x60, 0x0f, p2m_time_mul);
1517*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x61, 0x03, p2m_time_div);
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun 	msleep(100);
1520*4882a593Smuzhiyun 	dev_info(dev,
1521*4882a593Smuzhiyun 		"hs_prepare_zero num: 0x%02x, hs_trail num: 0x%02x, dsi_vsync_delay: 0x%02x, mipi DSI TX setting done !!!",
1522*4882a593Smuzhiyun 		mp_hs_pretime, mp_hs_endtime, bus->p2m_delay.tx_dsi_vsync_delay);
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun 
it6616_mipitx_setup_csi(struct it6616 * it6616)1525*4882a593Smuzhiyun static void it6616_mipitx_setup_csi(struct it6616 *it6616)//set_mptx
1526*4882a593Smuzhiyun {
1527*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1528*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1529*4882a593Smuzhiyun 	struct bus_para *bus = &it6616->mipi.bus_para_config;
1530*4882a593Smuzhiyun 	struct bus_config *cfg = &bus->cfg;
1531*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1532*4882a593Smuzhiyun 	u32 mp_hs_pretime = 0x4a;// int MPHSPreTime = 0x4a;//ori:11
1533*4882a593Smuzhiyun 	u32 mp_hs_endtime = 0x09;// int MPHSEndTime = 0x09;//ori:06
1534*4882a593Smuzhiyun 	u8 mp_vid_type = cfg->type;
1535*4882a593Smuzhiyun 	u32 mclk_ps = it6616->tx_mclk_ps, tx_mclk_mhz = it6616->tx_mclk / 1000;
1536*4882a593Smuzhiyun 	u32 mipi_tx_calc_hs_end_time = (6 * mclk_ps - 20 * 1000) / mclk_ps;
1537*4882a593Smuzhiyun 	u8 reg23, interlace, en_fs_fr_num = false;
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	reg23 = cfg->reg23_p2m;
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 	interlace = (it6616_hdmi_read(hdmi, 0x98) & 0x02) >> 1;
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	if (interlace)
1544*4882a593Smuzhiyun 		en_fs_fr_num = true;
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 	if (!it6616->mipi_tx_enable_manual_adjusted_d_phy) {
1547*4882a593Smuzhiyun 		mp_hs_pretime = (((145 + ((4 + bus->lpx_num) * 20)) * 1000 -
1548*4882a593Smuzhiyun 				((3 * mclk_ps) >> 1)) / mclk_ps);
1549*4882a593Smuzhiyun 		mp_hs_endtime = mipi_tx_calc_hs_end_time + 9;
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 		if (mipi_tx_calc_hs_end_time <= 0)
1552*4882a593Smuzhiyun 			mp_hs_endtime = 3;
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 		if (tx_mclk_mhz >= 300)
1555*4882a593Smuzhiyun 			mp_hs_pretime += 20;
1556*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 250)
1557*4882a593Smuzhiyun 			mp_hs_pretime += 18;
1558*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 200)
1559*4882a593Smuzhiyun 			mp_hs_pretime += 15;
1560*4882a593Smuzhiyun 		else if (tx_mclk_mhz >= 150)
1561*4882a593Smuzhiyun 			mp_hs_pretime += 12;
1562*4882a593Smuzhiyun 		else
1563*4882a593Smuzhiyun 			mp_hs_pretime += 9;
1564*4882a593Smuzhiyun 	} else {
1565*4882a593Smuzhiyun 		mp_hs_pretime = MIPI_TX_HS_PREPARE_ZERO;
1566*4882a593Smuzhiyun 		mp_hs_endtime = MIPI_TX_HS_TRAIL;
1567*4882a593Smuzhiyun 	}
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x1F, mp_hs_endtime);
1570*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x22, mp_hs_pretime);
1571*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x24, 0x20);
1572*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x25, bus->p2m_delay.tx_csi_p2m_delay);
1573*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x26, 0x20, (en_fs_fr_num << 5));
1574*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x27, 0x02);
1575*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x20, mp_vid_type);
1576*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x23, reg23);
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	msleep(100);
1579*4882a593Smuzhiyun 	dev_info(dev,
1580*4882a593Smuzhiyun 		"hs_prepare_zero num: 0x%02x, hs_trail num: 0x%02x, tx_csi_p2m_delay: 0x%02x, mipi CSI TX setting done !!!",
1581*4882a593Smuzhiyun 		mp_hs_pretime, mp_hs_endtime, bus->p2m_delay.tx_csi_p2m_delay);
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun 
it6616_mipi_tx_find_color_space_name_index(struct it6616 * it6616)1584*4882a593Smuzhiyun static u8 it6616_mipi_tx_find_color_space_name_index(struct it6616 *it6616)
1585*4882a593Smuzhiyun {
1586*4882a593Smuzhiyun 	u8 i, csi_dsi_index = (it6616->mipi.bus_type == MIPI_CSI) ? 0 : 1;
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(mipi_color_space[0]); i++) {
1589*4882a593Smuzhiyun 		if (it6616->mipi.data_type == mipi_color_space[csi_dsi_index][i])
1590*4882a593Smuzhiyun 			return i;
1591*4882a593Smuzhiyun 	}
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	return 0xFF;
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun 
it6616_mipitx_output_disable(struct it6616 * it6616)1596*4882a593Smuzhiyun static void it6616_mipitx_output_disable(struct it6616 *it6616)
1597*4882a593Smuzhiyun {
1598*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x05, 0x36);
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun 
it6616_mipi_tx_output_enable(struct it6616 * it6616)1603*4882a593Smuzhiyun static void it6616_mipi_tx_output_enable(struct it6616 *it6616)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 	/* release reset */
1608*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x05, 0x00);
1609*4882a593Smuzhiyun }
1610*4882a593Smuzhiyun 
it6616_mipi_tx_non_continuous_clock_setup(struct it6616 * it6616)1611*4882a593Smuzhiyun static void it6616_mipi_tx_non_continuous_clock_setup(struct it6616 *it6616)
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1614*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1615*4882a593Smuzhiyun 
1616*4882a593Smuzhiyun 	/* enable non continuous clock */
1617*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x44, 0x01, 0x00);
1618*4882a593Smuzhiyun 
1619*4882a593Smuzhiyun 	dev_info(dev, "set mipi tx non continuous clock");
1620*4882a593Smuzhiyun }
1621*4882a593Smuzhiyun 
it6616_mipitx_output_setup(struct it6616 * it6616)1622*4882a593Smuzhiyun static void it6616_mipitx_output_setup(struct it6616 *it6616)
1623*4882a593Smuzhiyun {
1624*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1625*4882a593Smuzhiyun 	struct bus_para *bus = &it6616->mipi.bus_para_config;
1626*4882a593Smuzhiyun 	struct bus_config *cfg = &bus->cfg;
1627*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1628*4882a593Smuzhiyun 	u8 color_space_name_index = it6616_mipi_tx_find_color_space_name_index(it6616);
1629*4882a593Smuzhiyun 	u8 bus_type_index = ((it6616->mipi.bus_type == MIPI_CSI) ? 0 : 1);
1630*4882a593Smuzhiyun 	u8 regb0, mplldiv, mprediv;
1631*4882a593Smuzhiyun 	u32 mclk_MHz;
1632*4882a593Smuzhiyun 	u32 pclk = it6616->vinfo.pclk / 1000;
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 	if (it6616->mipi_tx_enable_auto_adjust_lane_count)
1635*4882a593Smuzhiyun 		it6616->mipi.lane_cnt = it6616->csi_lanes_in_use;
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun adjust_lane_count:
1638*4882a593Smuzhiyun 	dev_info(dev, "%s", bus_type_index ? "MIPI_DSI" : "MIPI_CSI");
1639*4882a593Smuzhiyun 	dev_info(dev, "color space: %s", (color_space_name_index != 0xFF) ?
1640*4882a593Smuzhiyun 		mipi_color_space_name[bus_type_index][color_space_name_index] : "not find match");
1641*4882a593Smuzhiyun 	dev_info(dev, "lan_num: %d, swap_pn: %d", it6616->mipi.lane_cnt, bus->swap_pn);
1642*4882a593Smuzhiyun 	dev_info(dev, "swap_lan: %d, pclk_inv: %d", bus->swap_lan, bus->pclk_inv);
1643*4882a593Smuzhiyun 	dev_info(dev, "mclk_inv: %d, lpx_num: %d", bus->mclk_inv, bus->lpx_num);
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun 	it6616_mipitx_get_bus_config(it6616);
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 	if (pclk > 200)
1648*4882a593Smuzhiyun 		regb0 = cfg->regb0_div[0];
1649*4882a593Smuzhiyun 	else if (pclk > 100)
1650*4882a593Smuzhiyun 		regb0 = cfg->regb0_div[1];
1651*4882a593Smuzhiyun 	else
1652*4882a593Smuzhiyun 		regb0 = cfg->regb0_div[2];
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	mprediv = regb0 >> 5;
1655*4882a593Smuzhiyun 	mplldiv = regb0 & 0x1F;
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	dev_dbg(dev, "prediv: 0x%02x, plldiv: 0x%02x", mprediv, mplldiv);
1658*4882a593Smuzhiyun 
1659*4882a593Smuzhiyun 	mclk_MHz = ((pclk) * (mplldiv + 1)) >> 1;
1660*4882a593Smuzhiyun 	mclk_MHz = mclk_MHz / (mprediv + 1);
1661*4882a593Smuzhiyun 	it6616->tx_mclk = mclk_MHz * 1000;
1662*4882a593Smuzhiyun 	it6616->tx_mclk_ps = (2000 * (mprediv + 1) * 1000) / ((pclk) * (mplldiv + 1));
1663*4882a593Smuzhiyun 	dev_info(dev,
1664*4882a593Smuzhiyun 		"mclk_ns: %d.%d ns, mclk: %d MHz, pclk: %d MHz",
1665*4882a593Smuzhiyun 		it6616->tx_mclk_ps / 1000, it6616->tx_mclk_ps % 1000,
1666*4882a593Smuzhiyun 		it6616->tx_mclk / 1000, pclk);
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	if (it6616->mipi_tx_enable_auto_adjust_lane_count) {
1669*4882a593Smuzhiyun 		if (mclk_MHz < MIPI_TX_LANE_ADJUST_THRESHOLD) {
1670*4882a593Smuzhiyun 			it6616->mipi.lane_cnt = (it6616->mipi.lane_cnt == 4) ? 2 : 1;
1671*4882a593Smuzhiyun 			dev_info(dev, "mclk < %d MHz, adjust to lan_num: %d",
1672*4882a593Smuzhiyun 				MIPI_TX_LANE_ADJUST_THRESHOLD, it6616->mipi.lane_cnt);
1673*4882a593Smuzhiyun 			goto adjust_lane_count;
1674*4882a593Smuzhiyun 		}
1675*4882a593Smuzhiyun 	}
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	if (it6616->tx_mclk > 310000)
1678*4882a593Smuzhiyun 		bus->mclk_inv = 0;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x28, 0x0c, (bus->swap_pn << 3) | (bus->swap_lan << 2));
1681*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x10, BIT(2), bus->pclk_inv << 2);
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 	switch (it6616_mipi_tx_read(mipi, 0x04)) {
1684*4882a593Smuzhiyun 	case 0xC0:
1685*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x10, BIT(1), bus->mclk_inv << 1);
1686*4882a593Smuzhiyun 		break;
1687*4882a593Smuzhiyun 	default:
1688*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0x11, BIT(3), bus->mclk_inv << 3);
1689*4882a593Smuzhiyun 	}
1690*4882a593Smuzhiyun 
1691*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x8c, 0x40, 0x00);
1692*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x47, 0xf0, bus->mipi_tx_hs_prepare << 4);
1693*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x44, 0x04, bus->tx_enable_hs_pre_1T << 2);
1694*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x21, 0x30, (it6616->mipi.lane_cnt - 1) << 4);
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 	dev_dbg(dev, "set hs_prepare num: 0x%02x, hs_lpx num: 0x%02x",
1697*4882a593Smuzhiyun 		bus->mipi_tx_hs_prepare, bus->lpx_num);
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun 	if ((pclk < (10 * (mprediv + 1))) || (pclk > (100 * (mprediv + 1))))
1700*4882a593Smuzhiyun 		dev_err(dev,
1701*4882a593Smuzhiyun 			"MPTX PHY setting wrong, need to reset parameter for TXPHY!!!");
1702*4882a593Smuzhiyun 
1703*4882a593Smuzhiyun 	if (it6616->mipi.bus_type == MIPI_CSI) {
1704*4882a593Smuzhiyun 		if (pclk >= (mclk_MHz * 2))
1705*4882a593Smuzhiyun 			bus->p2m_delay.tx_csi_p2m_delay = 0x02;
1706*4882a593Smuzhiyun 		else if (pclk >= mclk_MHz)
1707*4882a593Smuzhiyun 			bus->p2m_delay.tx_csi_p2m_delay = 0x04;
1708*4882a593Smuzhiyun 		else if (mclk_MHz >= (pclk * 2))
1709*4882a593Smuzhiyun 			bus->p2m_delay.tx_csi_p2m_delay = 0x0a;
1710*4882a593Smuzhiyun 		else if ((mclk_MHz * 2) >= (pclk * 3))
1711*4882a593Smuzhiyun 			bus->p2m_delay.tx_csi_p2m_delay = 0x08;
1712*4882a593Smuzhiyun 		else
1713*4882a593Smuzhiyun 			bus->p2m_delay.tx_csi_p2m_delay = 0x04;
1714*4882a593Smuzhiyun 		it6616_mipitx_setup_csi(it6616);
1715*4882a593Smuzhiyun 	} else {
1716*4882a593Smuzhiyun 		if (pclk >= (mclk_MHz * 2))
1717*4882a593Smuzhiyun 			bus->p2m_delay.tx_dsi_vsync_delay = 0x02;
1718*4882a593Smuzhiyun 		else if (pclk >= mclk_MHz)
1719*4882a593Smuzhiyun 			bus->p2m_delay.tx_dsi_vsync_delay = 0x04;
1720*4882a593Smuzhiyun 		else if (mclk_MHz >= (pclk * 2))
1721*4882a593Smuzhiyun 			bus->p2m_delay.tx_dsi_vsync_delay = 0x0a;
1722*4882a593Smuzhiyun 		else if ((mclk_MHz * 2) >= (pclk * 3))
1723*4882a593Smuzhiyun 			bus->p2m_delay.tx_dsi_vsync_delay = 0x08;
1724*4882a593Smuzhiyun 		else
1725*4882a593Smuzhiyun 			bus->p2m_delay.tx_dsi_vsync_delay = 0x04;
1726*4882a593Smuzhiyun 		it6616_mipitx_setup_dsi(it6616);
1727*4882a593Smuzhiyun 	}
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	if (!it6616->mipi_tx_enable_continuous_clock)
1730*4882a593Smuzhiyun 		it6616_mipi_tx_non_continuous_clock_setup(it6616);
1731*4882a593Smuzhiyun 
1732*4882a593Smuzhiyun 	/* setup mipi-tx-afe */
1733*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0xb0, regb0);
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	msleep(100);
1736*4882a593Smuzhiyun }
1737*4882a593Smuzhiyun 
it6616_enable_mipi(struct it6616 * it6616)1738*4882a593Smuzhiyun static void it6616_enable_mipi(struct it6616 *it6616)
1739*4882a593Smuzhiyun {
1740*4882a593Smuzhiyun 	it6616_mipitx_output_setup(it6616);
1741*4882a593Smuzhiyun 	it6616_mipi_tx_output_enable(it6616);
1742*4882a593Smuzhiyun 	it6616->mipi_tx_enable_mipi_output = 1;
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun 
it6616_disable_mipi(struct it6616 * it6616)1745*4882a593Smuzhiyun static void it6616_disable_mipi(struct it6616 *it6616)
1746*4882a593Smuzhiyun {
1747*4882a593Smuzhiyun 	it6616_mipitx_output_disable(it6616);
1748*4882a593Smuzhiyun 	it6616->mipi_tx_enable_mipi_output = 0;
1749*4882a593Smuzhiyun }
1750*4882a593Smuzhiyun 
it6616_mipi_tx_get_support_format(struct it6616 * it6616)1751*4882a593Smuzhiyun static void it6616_mipi_tx_get_support_format(struct it6616 *it6616)
1752*4882a593Smuzhiyun {
1753*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1754*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1755*4882a593Smuzhiyun 	u8 mipi_intput_color = it6616->mipi.data_type;
1756*4882a593Smuzhiyun 	u8 color_space_name_index;
1757*4882a593Smuzhiyun 	u8 bus_type_index = ((it6616->mipi.bus_type == MIPI_CSI) ? 0 : 1);
1758*4882a593Smuzhiyun 
1759*4882a593Smuzhiyun 	if (it6616->mipi.bus_type == MIPI_CSI) {
1760*4882a593Smuzhiyun 		switch (mipi_intput_color) {
1761*4882a593Smuzhiyun 		case CSI_RGB10b:
1762*4882a593Smuzhiyun 			dev_dbg(dev, "csi not support CSI_RGB10b");
1763*4882a593Smuzhiyun 			it6616->mipi.data_type = CSI_RGB888;
1764*4882a593Smuzhiyun 			break;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 		case CSI_YCbCr42212b:
1767*4882a593Smuzhiyun 			dev_dbg(dev, "csi not support CSI_YCbCr42212b");
1768*4882a593Smuzhiyun 			it6616->mipi.data_type = CSI_YCbCr4228b;
1769*4882a593Smuzhiyun 			break;
1770*4882a593Smuzhiyun 
1771*4882a593Smuzhiyun 		default:
1772*4882a593Smuzhiyun 			return;
1773*4882a593Smuzhiyun 		}
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 		color_space_name_index = it6616_mipi_tx_find_color_space_name_index(it6616);
1776*4882a593Smuzhiyun 
1777*4882a593Smuzhiyun 		if (color_space_name_index != 0xFF)
1778*4882a593Smuzhiyun 			dev_dbg(dev,
1779*4882a593Smuzhiyun 				"will set %s",
1780*4882a593Smuzhiyun 				mipi_color_space_name[bus_type_index][color_space_name_index]);
1781*4882a593Smuzhiyun 		else
1782*4882a593Smuzhiyun 			dev_err(dev, "error not find match color space");
1783*4882a593Smuzhiyun 	} else {
1784*4882a593Smuzhiyun 		if (it6616_mipi_tx_read(mipi, 0x04) == 0xC0) {
1785*4882a593Smuzhiyun 			if ((mipi_intput_color == DSI_YCbCr_16b) ||
1786*4882a593Smuzhiyun 				(mipi_intput_color == DSI_YCbCr_20b) ||
1787*4882a593Smuzhiyun 				(mipi_intput_color == DSI_YCbCr_24b)) {
1788*4882a593Smuzhiyun 				mipi_intput_color = it6616->mipi.data_type = DSI_RGB_24b;
1789*4882a593Smuzhiyun 				dev_dbg(dev, "0xC0 MIPI DSI only support RGB, using: DSI_RGB_24b(%d)",
1790*4882a593Smuzhiyun 					mipi_intput_color);
1791*4882a593Smuzhiyun 			}
1792*4882a593Smuzhiyun 		}
1793*4882a593Smuzhiyun 	}
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun 
1796*4882a593Smuzhiyun /*
1797*4882a593Smuzhiyun  * mipi rx need pn swap and let first bit data(after SOT) will be rising edge
1798*4882a593Smuzhiyun  * can use in it6616_mipitx_initial function before it6616_mipi_tx_write_lp_cmds
1799*4882a593Smuzhiyun  */
it6616_mipi_tx_rk_fix_first_bit_issue(struct it6616 * it6616)1800*4882a593Smuzhiyun static __maybe_unused void it6616_mipi_tx_rk_fix_first_bit_issue(struct it6616 *it6616)
1801*4882a593Smuzhiyun {
1802*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x05, 0x00);
1805*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x28, 0x08, 0x08);
1806*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x04);
1807*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x28, 0x08, 0x00);
1808*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x70, 0x04, 0x00);
1809*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x05, 0x36);
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun 
it6616_mipitx_initial(struct it6616 * it6616)1812*4882a593Smuzhiyun static void it6616_mipitx_initial(struct it6616 *it6616)
1813*4882a593Smuzhiyun {
1814*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
1815*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
1816*4882a593Smuzhiyun 	struct bus_para *bus = &it6616->mipi.bus_para_config;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x05, 0x09, 0x09);
1819*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x05, 0x36);
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x2A, 0x3c, 0x00);
1822*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x3c, 0x20, 0x20);
1823*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x6b, 0x01, it6616->mipi.bus_type);
1824*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x10, 0x80, bus->tx_bypass << 7);
1825*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0xc1, 0x03, 0x03);
1826*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0xa8, 0x01, 0x00);
1827*4882a593Smuzhiyun 	it6616_mipi_tx_set_bits(mipi, 0x45, 0x0f, bus->lpx_num);
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	if (it6616->mipi_tx_enable_initial_fire_lp_cmd) {
1830*4882a593Smuzhiyun 		it6616_mipi_tx_write_lp_cmds(it6616, dcs_table, ARRAY_SIZE(dcs_table),
1831*4882a593Smuzhiyun 						SET_DISPLAY_ON, 2, CALC_HEADER);
1832*4882a593Smuzhiyun 		it6616_mipi_tx_write(mipi, 0x05, 0x36);
1833*4882a593Smuzhiyun 	}
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	dev_dbg(dev, "mipi_initial chip:0x%02x", it6616_mipi_tx_read(mipi, 0x04));
1836*4882a593Smuzhiyun }
1837*4882a593Smuzhiyun 
it6616_hdmi_is_5v_on(struct it6616 * it6616)1838*4882a593Smuzhiyun static bool it6616_hdmi_is_5v_on(struct it6616 *it6616)
1839*4882a593Smuzhiyun {
1840*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	if (it6616_hdmi_read(hdmi, 0x13) & 0x01)
1843*4882a593Smuzhiyun 		return true;
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 	return false;
1846*4882a593Smuzhiyun }
1847*4882a593Smuzhiyun 
it6616_hdmi_is_clock_stable(struct it6616 * it6616)1848*4882a593Smuzhiyun static bool it6616_hdmi_is_clock_stable(struct it6616 *it6616)
1849*4882a593Smuzhiyun {
1850*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun 	if (it6616_hdmi_read(hdmi, 0x13) & 0x10)
1853*4882a593Smuzhiyun 		return true;
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 	return false;
1856*4882a593Smuzhiyun }
1857*4882a593Smuzhiyun 
it6616_hdmi_is_symbol_locked(struct it6616 * it6616)1858*4882a593Smuzhiyun static __maybe_unused bool it6616_hdmi_is_symbol_locked(struct it6616 *it6616)
1859*4882a593Smuzhiyun {
1860*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1861*4882a593Smuzhiyun 	u8 reg14;
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun 	reg14 = it6616_hdmi_read(hdmi, 0x14);
1864*4882a593Smuzhiyun 	if ((reg14 & 0x38) == 0x38)
1865*4882a593Smuzhiyun 		return true;
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	return false;
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun 
it6616_hdmi_is_scdt_on(struct it6616 * it6616)1870*4882a593Smuzhiyun static bool it6616_hdmi_is_scdt_on(struct it6616 *it6616)
1871*4882a593Smuzhiyun {
1872*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	if (it6616_hdmi_read(hdmi, 0x19) & BIT(7))
1875*4882a593Smuzhiyun 		return true;
1876*4882a593Smuzhiyun 
1877*4882a593Smuzhiyun 	return false;
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun 
it6616_hdmi_get_output_color_space(struct it6616 * it6616)1880*4882a593Smuzhiyun static u8 it6616_hdmi_get_output_color_space(struct it6616 *it6616)
1881*4882a593Smuzhiyun {
1882*4882a593Smuzhiyun 	u8 hdmi_output_color = 0;
1883*4882a593Smuzhiyun 	u8 mipi_intput_color = it6616->mipi.data_type;
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun 	if (it6616->mipi.bus_type == MIPI_CSI) {
1886*4882a593Smuzhiyun 		switch (mipi_intput_color) {
1887*4882a593Smuzhiyun 		case CSI_RGB10b:
1888*4882a593Smuzhiyun 		case CSI_RGB888:
1889*4882a593Smuzhiyun 		case CSI_RGB666:
1890*4882a593Smuzhiyun 		case CSI_RGB565:
1891*4882a593Smuzhiyun 		case CSI_RGB555:
1892*4882a593Smuzhiyun 		case CSI_RGB444:
1893*4882a593Smuzhiyun 			hdmi_output_color = HDMI_COLORSPACE_RGB;
1894*4882a593Smuzhiyun 			break;
1895*4882a593Smuzhiyun 		case CSI_YCbCr4208b:
1896*4882a593Smuzhiyun 			hdmi_output_color = HDMI_COLORSPACE_YUV420;
1897*4882a593Smuzhiyun 			break;
1898*4882a593Smuzhiyun 		case CSI_YCbCr4228b:
1899*4882a593Smuzhiyun 		case CSI_YCbCr42210b:
1900*4882a593Smuzhiyun 		case CSI_YCbCr42212b:
1901*4882a593Smuzhiyun 			hdmi_output_color = HDMI_COLORSPACE_YUV422;
1902*4882a593Smuzhiyun 			break;
1903*4882a593Smuzhiyun 		}
1904*4882a593Smuzhiyun 	} else {
1905*4882a593Smuzhiyun 		switch (mipi_intput_color) {
1906*4882a593Smuzhiyun 		case DSI_RGB_36b:
1907*4882a593Smuzhiyun 		case DSI_RGB_30b:
1908*4882a593Smuzhiyun 		case DSI_RGB_24b:
1909*4882a593Smuzhiyun 		case DSI_RGB_18b_L:
1910*4882a593Smuzhiyun 		case DSI_RGB_18b:
1911*4882a593Smuzhiyun 			hdmi_output_color = HDMI_COLORSPACE_RGB;
1912*4882a593Smuzhiyun 			break;
1913*4882a593Smuzhiyun 		case DSI_YCbCr_16b:
1914*4882a593Smuzhiyun 		case DSI_YCbCr_20b:
1915*4882a593Smuzhiyun 		case DSI_YCbCr_24b:
1916*4882a593Smuzhiyun 			hdmi_output_color = HDMI_COLORSPACE_YUV422;
1917*4882a593Smuzhiyun 			break;
1918*4882a593Smuzhiyun 		}
1919*4882a593Smuzhiyun 	}
1920*4882a593Smuzhiyun 	it6616->output_colorspace = hdmi_output_color;
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun 	return hdmi_output_color;
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun 
it6616_hdmi_edid_ram_get(struct it6616 * it6616,u8 * buf)1925*4882a593Smuzhiyun static void it6616_hdmi_edid_ram_get(struct it6616 *it6616, u8 *buf)
1926*4882a593Smuzhiyun {
1927*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1928*4882a593Smuzhiyun 	struct regmap *edid = it6616->edid_regmap;
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x4B, (I2C_ADR_EDID | 0x01));
1931*4882a593Smuzhiyun 	it6616_hdmi_edid_read(edid, buf, 0, 256);
1932*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x4B, (I2C_ADR_EDID));
1933*4882a593Smuzhiyun }
1934*4882a593Smuzhiyun 
it6616_hdmi_edid_ram_update_chksum(struct it6616 * it6616)1935*4882a593Smuzhiyun static void it6616_hdmi_edid_ram_update_chksum(struct it6616 *it6616)
1936*4882a593Smuzhiyun {
1937*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1938*4882a593Smuzhiyun 	u16 sum;
1939*4882a593Smuzhiyun 	u8 offset;
1940*4882a593Smuzhiyun 	int i;
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	// cal block 0 sum
1943*4882a593Smuzhiyun 	sum = 0;
1944*4882a593Smuzhiyun 	for (i = 0 ; i < 127 ; i++)
1945*4882a593Smuzhiyun 		sum += it6616->edid_data[i];
1946*4882a593Smuzhiyun 	sum = (0x100 - sum) & 0xFF;
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0xC9, sum);
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	// cal block 1 sum
1951*4882a593Smuzhiyun 	sum = 0;
1952*4882a593Smuzhiyun 	offset = it6616_hdmi_read(hdmi, 0xC6);
1953*4882a593Smuzhiyun 	for (i = 128; i < 128 + 127; i++)
1954*4882a593Smuzhiyun 		sum += it6616->edid_data[i];
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	sum -= it6616->edid_data[offset];
1957*4882a593Smuzhiyun 	sum -= it6616->edid_data[offset + 1];
1958*4882a593Smuzhiyun 	sum += it6616_hdmi_read(hdmi, 0xC7);
1959*4882a593Smuzhiyun 	sum += it6616_hdmi_read(hdmi, 0xC8);
1960*4882a593Smuzhiyun 	sum = (0x100 - sum) & 0xFF;
1961*4882a593Smuzhiyun 
1962*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0xCA, sum);
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun 
it6616_hdmi_edid_ram_init(struct it6616 * it6616)1965*4882a593Smuzhiyun static void it6616_hdmi_edid_ram_init(struct it6616 *it6616)
1966*4882a593Smuzhiyun {
1967*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1968*4882a593Smuzhiyun 	struct regmap *edid = it6616->edid_regmap;
1969*4882a593Smuzhiyun 	unsigned int phy_addr_off;
1970*4882a593Smuzhiyun 	u16 addr;
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun 	// write data to EDID RAM
1973*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x4B, (I2C_ADR_EDID | 0x01));
1974*4882a593Smuzhiyun 	it6616_hdmi_edid_write(edid, it6616->edid_data, 0, it6616->edid_len);
1975*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x4B, (I2C_ADR_EDID));
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	// update physical address for VSDB
1978*4882a593Smuzhiyun 	addr = cec_get_edid_phys_addr(it6616->edid_data, it6616->edid_len, &phy_addr_off);
1979*4882a593Smuzhiyun 	if (addr != CEC_PHYS_ADDR_INVALID) {
1980*4882a593Smuzhiyun 		it6616_hdmi_write(hdmi, 0xC6, (u8)phy_addr_off); // VSDB start address
1981*4882a593Smuzhiyun 		it6616_hdmi_write(hdmi, 0xC7, (addr >> 8) & 0xFF); // addr AB
1982*4882a593Smuzhiyun 		it6616_hdmi_write(hdmi, 0xC8, addr & 0xFF); // addr CD
1983*4882a593Smuzhiyun 	}
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 	// recalculate block0/block1 checksum
1986*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_update_chksum(it6616);
1987*4882a593Smuzhiyun 
1988*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0xC5, 0x10, 0x10);
1989*4882a593Smuzhiyun 	msleep(20);
1990*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0xC5, 0x10, 0x00);
1991*4882a593Smuzhiyun }
1992*4882a593Smuzhiyun 
it6616_hdmi_video_reset(struct it6616 * it6616)1993*4882a593Smuzhiyun static void it6616_hdmi_video_reset(struct it6616 *it6616)
1994*4882a593Smuzhiyun {
1995*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
1996*4882a593Smuzhiyun 
1997*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x22, BIT(0), BIT(0));
1998*4882a593Smuzhiyun 	msleep(20);
1999*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x22, BIT(0), 0x00);
2000*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x10, BIT(1), BIT(1)); // clear vidstable change INT
2001*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x12, BIT(7), BIT(7)); // clear vidstable change INT
2002*4882a593Smuzhiyun }
2003*4882a593Smuzhiyun 
it6616_hdmi_edid_ram_enable(struct it6616 * it6616,u8 enabled)2004*4882a593Smuzhiyun static void it6616_hdmi_edid_ram_enable(struct it6616 *it6616, u8 enabled)
2005*4882a593Smuzhiyun {
2006*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	if (enabled)
2009*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0xC5, 0x3F, 0x02);
2010*4882a593Smuzhiyun 	else
2011*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0xC5, 0x3F, 0x13);
2012*4882a593Smuzhiyun }
2013*4882a593Smuzhiyun 
it6616_hdmi_rx_get_video_info(struct it6616 * it6616)2014*4882a593Smuzhiyun static void it6616_hdmi_rx_get_video_info(struct it6616 *it6616)
2015*4882a593Smuzhiyun {
2016*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2017*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2018*4882a593Smuzhiyun 	u16 h_sync_pol, v_sync_pol, interlaced;
2019*4882a593Smuzhiyun 	u16 h_total, h_active, h_front_porch, h_sync_w;
2020*4882a593Smuzhiyun 	u16 v_total, v_active, v_front_porch, v_sync_w;
2021*4882a593Smuzhiyun 	u32 frame_rate;
2022*4882a593Smuzhiyun 
2023*4882a593Smuzhiyun 	interlaced = (it6616_hdmi_read(hdmi, 0x98) & 0x02) >> 1;
2024*4882a593Smuzhiyun 
2025*4882a593Smuzhiyun 	h_total = ((it6616_hdmi_read(hdmi, 0x9C) & 0x3F) << 8) + it6616_hdmi_read(hdmi, 0x9B);
2026*4882a593Smuzhiyun 	h_active = ((it6616_hdmi_read(hdmi, 0x9E) & 0x3F) << 8) + it6616_hdmi_read(hdmi, 0x9D);
2027*4882a593Smuzhiyun 	h_front_porch = ((it6616_hdmi_read(hdmi, 0xA1) & 0xF0) << 4) + it6616_hdmi_read(hdmi, 0xA0);
2028*4882a593Smuzhiyun 	h_sync_w = ((it6616_hdmi_read(hdmi, 0xA1) & 0x01) << 8) + it6616_hdmi_read(hdmi, 0x9F);
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	v_total = ((it6616_hdmi_read(hdmi, 0xA3) & 0x3F) << 8) + it6616_hdmi_read(hdmi, 0xA2);
2031*4882a593Smuzhiyun 	v_active = ((it6616_hdmi_read(hdmi, 0xA5) & 0x3F) << 8) + it6616_hdmi_read(hdmi, 0xA4);
2032*4882a593Smuzhiyun 	v_front_porch = ((it6616_hdmi_read(hdmi, 0xA8) & 0xF0) << 4) + it6616_hdmi_read(hdmi, 0xA7);
2033*4882a593Smuzhiyun 	v_sync_w = ((it6616_hdmi_read(hdmi, 0xA8) & 0x01) << 8) + it6616_hdmi_read(hdmi, 0xA6);
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 	h_sync_pol = (it6616_hdmi_read(hdmi, 0xAA) & BIT(5)) >> 5;
2036*4882a593Smuzhiyun 	v_sync_pol = (it6616_hdmi_read(hdmi, 0xAA) & BIT(6)) >> 6;
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun 	it6616->vinfo.h_active = h_active;
2039*4882a593Smuzhiyun 	it6616->vinfo.h_total = h_total;
2040*4882a593Smuzhiyun 	it6616->vinfo.h_front_porch = h_front_porch;
2041*4882a593Smuzhiyun 	it6616->vinfo.h_sync_w = h_sync_w;
2042*4882a593Smuzhiyun 	it6616->vinfo.h_back_porch = (h_total - h_active - h_front_porch - h_sync_w);
2043*4882a593Smuzhiyun 	it6616->vinfo.v_active = v_active;
2044*4882a593Smuzhiyun 	it6616->vinfo.v_total = v_total;
2045*4882a593Smuzhiyun 	it6616->vinfo.v_front_porch = v_front_porch;
2046*4882a593Smuzhiyun 	it6616->vinfo.v_sync_w = v_sync_w;
2047*4882a593Smuzhiyun 	it6616->vinfo.v_back_porch = v_total - v_active - v_front_porch - v_sync_w;
2048*4882a593Smuzhiyun 	it6616->vinfo.interlaced = (interlaced) & 0x01;
2049*4882a593Smuzhiyun 	it6616->vinfo.v_sync_pol = (v_sync_pol) & 0x01;
2050*4882a593Smuzhiyun 	it6616->vinfo.h_sync_pol = (h_sync_pol) & 0x01;
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 	frame_rate = (u32)(it6616->vinfo.pclk) * 1000;
2053*4882a593Smuzhiyun 	frame_rate /= it6616->vinfo.h_total;
2054*4882a593Smuzhiyun 	frame_rate /= it6616->vinfo.v_total;
2055*4882a593Smuzhiyun 	it6616->vinfo.frame_rate = frame_rate;
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun 	if (it6616->avi_if.colorspace == HDMI_COLORSPACE_YUV420) {
2058*4882a593Smuzhiyun 		dev_dbg(dev, "HActive = %d\n", it6616->vinfo.h_active*2);
2059*4882a593Smuzhiyun 		dev_dbg(dev, "HTotal = %d\n", it6616->vinfo.h_total*2);
2060*4882a593Smuzhiyun 	} else {
2061*4882a593Smuzhiyun 		dev_dbg(dev, "HActive = %d\n", it6616->vinfo.h_active);
2062*4882a593Smuzhiyun 		dev_dbg(dev, "HTotal = %d\n", it6616->vinfo.h_total);
2063*4882a593Smuzhiyun 	}
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	dev_dbg(dev, "VActive = %d\n", it6616->vinfo.v_active);
2066*4882a593Smuzhiyun 	dev_dbg(dev, "VTotal = %d\n", it6616->vinfo.v_total);
2067*4882a593Smuzhiyun 
2068*4882a593Smuzhiyun 	if (it6616->avi_if.colorspace == HDMI_COLORSPACE_YUV420) {
2069*4882a593Smuzhiyun 		dev_dbg(dev, "HFrontPorch = %d\n", it6616->vinfo.h_front_porch*2);
2070*4882a593Smuzhiyun 		dev_dbg(dev, "HSyncWidth = %d\n", it6616->vinfo.h_sync_w*2);
2071*4882a593Smuzhiyun 		dev_dbg(dev, "HBackPorch = %d\n", it6616->vinfo.h_back_porch*2);
2072*4882a593Smuzhiyun 	} else {
2073*4882a593Smuzhiyun 		dev_dbg(dev, "HFrontPorch = %d\n", it6616->vinfo.h_front_porch);
2074*4882a593Smuzhiyun 		dev_dbg(dev, "HSyncWidth = %d\n", it6616->vinfo.h_sync_w);
2075*4882a593Smuzhiyun 		dev_dbg(dev, "HBackPorch = %d\n", it6616->vinfo.h_back_porch);
2076*4882a593Smuzhiyun 	}
2077*4882a593Smuzhiyun 
2078*4882a593Smuzhiyun 	dev_dbg(dev, "VFrontPorch = %d\n", it6616->vinfo.v_front_porch);
2079*4882a593Smuzhiyun 	dev_dbg(dev, "VSyncWidth = %d\n", it6616->vinfo.v_sync_w);
2080*4882a593Smuzhiyun 	dev_dbg(dev, "VBackPorch = %d\n", it6616->vinfo.v_back_porch);
2081*4882a593Smuzhiyun 	dev_dbg(dev, "FrameRate = %u\n", it6616->vinfo.frame_rate);
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	if (it6616->vinfo.interlaced)
2084*4882a593Smuzhiyun 		dev_dbg(dev, "ScanMode = InterLaced\n");
2085*4882a593Smuzhiyun 	else
2086*4882a593Smuzhiyun 		dev_dbg(dev, "ScanMode = Progressive\n");
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	if (it6616->vinfo.v_sync_pol)
2089*4882a593Smuzhiyun 		dev_dbg(dev, "VSyncPol = Positive\n");
2090*4882a593Smuzhiyun 	else
2091*4882a593Smuzhiyun 		dev_dbg(dev, "VSyncPol = Negative\n");
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	if (it6616->vinfo.h_sync_pol)
2094*4882a593Smuzhiyun 		dev_dbg(dev, "HSyncPol = Positive\n");
2095*4882a593Smuzhiyun 	else
2096*4882a593Smuzhiyun 		dev_dbg(dev, "HSyncPol = Negative");
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun 
it6616_hdmi_hpd_output(struct it6616 * it6616,u8 hpd)2099*4882a593Smuzhiyun static void it6616_hdmi_hpd_output(struct it6616 *it6616, u8 hpd)
2100*4882a593Smuzhiyun {
2101*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2102*4882a593Smuzhiyun 
2103*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 3);
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 	if (hpd)
2106*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0xAB, 0xC0, 0xC0); // SET PORT0 HPD HIGH
2107*4882a593Smuzhiyun 	else
2108*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0xAB, 0xC0, 0x40); // SET PORT0 HPD LOW
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2111*4882a593Smuzhiyun }
2112*4882a593Smuzhiyun 
it6616_hdmi_hdcp_reset(struct it6616 * it6616)2113*4882a593Smuzhiyun static void it6616_hdmi_hdcp_reset(struct it6616 *it6616)
2114*4882a593Smuzhiyun {
2115*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2116*4882a593Smuzhiyun 
2117*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x23, 0x02, 0x02);
2118*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x23, 0x02, 0x00);
2119*4882a593Smuzhiyun }
2120*4882a593Smuzhiyun 
it6616_hdmi_get_hdcp_status(struct it6616 * it6616)2121*4882a593Smuzhiyun static bool it6616_hdmi_get_hdcp_status(struct it6616 *it6616)
2122*4882a593Smuzhiyun {
2123*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 	return it6616_hdmi_read(hdmi, 0xCF) & BIT(5);
2126*4882a593Smuzhiyun }
2127*4882a593Smuzhiyun 
it6616_get_hdcp_status(struct it6616 * it6616)2128*4882a593Smuzhiyun static bool it6616_get_hdcp_status(struct it6616 *it6616)
2129*4882a593Smuzhiyun {
2130*4882a593Smuzhiyun 	bool hdcp_status;
2131*4882a593Smuzhiyun 
2132*4882a593Smuzhiyun 	hdcp_status = it6616_hdmi_get_hdcp_status(it6616);
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 	return hdcp_status;
2135*4882a593Smuzhiyun }
2136*4882a593Smuzhiyun 
it6616_hdmi_rx_get_av_mute_state(struct it6616 * it6616)2137*4882a593Smuzhiyun static enum av_mute_state it6616_hdmi_rx_get_av_mute_state(struct it6616 *it6616)
2138*4882a593Smuzhiyun {
2139*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2140*4882a593Smuzhiyun 	bool av_mute_state;
2141*4882a593Smuzhiyun 
2142*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2143*4882a593Smuzhiyun 	av_mute_state = !!(it6616_hdmi_read(hdmi, 0xAA) & BIT(3));
2144*4882a593Smuzhiyun 
2145*4882a593Smuzhiyun 	return av_mute_state ? AV_MUTE_ON : AV_MUTE_OFF;
2146*4882a593Smuzhiyun }
2147*4882a593Smuzhiyun 
it6616_hdmi_rx_set_av_mute(struct it6616 * it6616,enum av_mute_state mute_state)2148*4882a593Smuzhiyun static void it6616_hdmi_rx_set_av_mute(struct it6616 *it6616, enum av_mute_state mute_state)
2149*4882a593Smuzhiyun {
2150*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2153*4882a593Smuzhiyun 
2154*4882a593Smuzhiyun 	switch (mute_state) {
2155*4882a593Smuzhiyun 	case AV_MUTE_OFF:
2156*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x4F, BIT(5), 0x00);
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 		if (!it6616->mipi_tx_enable_mipi_output) {
2159*4882a593Smuzhiyun 			it6616_hdmi_rx_get_video_info(it6616);
2160*4882a593Smuzhiyun 			it6616_mipi_tx_get_support_format(it6616);
2161*4882a593Smuzhiyun 			it6616_enable_mipi(it6616);
2162*4882a593Smuzhiyun 		}
2163*4882a593Smuzhiyun 		break;
2164*4882a593Smuzhiyun 	case AV_MUTE_ON:
2165*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x4F, BIT(5), BIT(5));
2166*4882a593Smuzhiyun 		it6616_disable_mipi(it6616);
2167*4882a593Smuzhiyun 		break;
2168*4882a593Smuzhiyun 	default:
2169*4882a593Smuzhiyun 		break;
2170*4882a593Smuzhiyun 	}
2171*4882a593Smuzhiyun }
2172*4882a593Smuzhiyun 
it6616_hdmi_update_rs(struct it6616 * it6616,u8 level)2173*4882a593Smuzhiyun static void it6616_hdmi_update_rs(struct it6616 *it6616, u8 level)
2174*4882a593Smuzhiyun {
2175*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2176*4882a593Smuzhiyun 	u8 rs_val = level;
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 3);
2179*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x26, 0x20, 0x00);
2180*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x27, rs_val);
2181*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x28, rs_val);
2182*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x29, rs_val);
2183*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2184*4882a593Smuzhiyun }
2185*4882a593Smuzhiyun 
it6616_mipi_tx_calc_rclk(struct it6616 * it6616)2186*4882a593Smuzhiyun static void it6616_mipi_tx_calc_rclk(struct it6616 *it6616)
2187*4882a593Smuzhiyun {
2188*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
2189*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
2190*4882a593Smuzhiyun 	unsigned long sum = 0, ul100msCNT = 0;
2191*4882a593Smuzhiyun 	u8 i, retry = 3;
2192*4882a593Smuzhiyun 
2193*4882a593Smuzhiyun 	for (i = 0; i < retry; i++) {
2194*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE0, 0x80, 0x80); // Enable RCLK 100ms count
2195*4882a593Smuzhiyun 		msleep(100);
2196*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE0, 0x80, 0x00); // Disable RCLK 100ms count
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 		ul100msCNT = it6616_mipi_tx_read(mipi, 0xE3);
2199*4882a593Smuzhiyun 		ul100msCNT = ((ul100msCNT << 8) | (it6616_mipi_tx_read(mipi, 0xE2)));
2200*4882a593Smuzhiyun 		ul100msCNT = ((ul100msCNT << 8) | (it6616_mipi_tx_read(mipi, 0xE1)));
2201*4882a593Smuzhiyun 
2202*4882a593Smuzhiyun 		sum += ul100msCNT;
2203*4882a593Smuzhiyun 	}
2204*4882a593Smuzhiyun 	sum /= retry;
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 	it6616->tx_rclk = sum / TIMER_100MS;
2207*4882a593Smuzhiyun 	dev_dbg(dev, "mipi rclk = %d.%d MHz", it6616->tx_rclk / 1000,
2208*4882a593Smuzhiyun 		it6616->tx_rclk % 1000);
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun 
it6616_mipi_tx_calc_mclk(struct it6616 * it6616)2211*4882a593Smuzhiyun static void it6616_mipi_tx_calc_mclk(struct it6616 *it6616)
2212*4882a593Smuzhiyun {
2213*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
2214*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
2215*4882a593Smuzhiyun 	unsigned long sum = 0, ulCNT, tx_mclk;
2216*4882a593Smuzhiyun 	u8 i, retry = 3;
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	for (i = 0; i < retry; i++) {
2219*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE7, 0x80, 0x80);
2220*4882a593Smuzhiyun 		msleep(20);
2221*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE7, 0x80, 0x00);
2222*4882a593Smuzhiyun 
2223*4882a593Smuzhiyun 		ulCNT = it6616_mipi_tx_read(mipi, 0xE7) & 0x0F;
2224*4882a593Smuzhiyun 		ulCNT = (it6616_mipi_tx_read(mipi, 0xE6) | (ulCNT << 8));
2225*4882a593Smuzhiyun 
2226*4882a593Smuzhiyun 		sum += ulCNT;
2227*4882a593Smuzhiyun 	}
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun 	sum /= retry;
2230*4882a593Smuzhiyun 
2231*4882a593Smuzhiyun 	//MCLK = 13500*2048/sum;
2232*4882a593Smuzhiyun 	//MCLK = 27000*2048/sum;
2233*4882a593Smuzhiyun 	tx_mclk = it6616->tx_rclk * 2048 / sum;
2234*4882a593Smuzhiyun 	dev_dbg(dev, "mipi mclk = %lu.%lu MHz", tx_mclk / 1000, tx_mclk % 1000);
2235*4882a593Smuzhiyun }
2236*4882a593Smuzhiyun 
it6616_mipi_tx_calc_pclk(struct it6616 * it6616)2237*4882a593Smuzhiyun static void it6616_mipi_tx_calc_pclk(struct it6616 *it6616)
2238*4882a593Smuzhiyun {
2239*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
2240*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
2241*4882a593Smuzhiyun 	unsigned long sum = 0, ulCNT;
2242*4882a593Smuzhiyun 	u8 i, retry = 3;
2243*4882a593Smuzhiyun 
2244*4882a593Smuzhiyun 	for (i = 0; i < retry; i++) {
2245*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE5, 0x80, 0x80);
2246*4882a593Smuzhiyun 		msleep(20);
2247*4882a593Smuzhiyun 		it6616_mipi_tx_set_bits(mipi, 0xE5, 0x80, 0x00);
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 		ulCNT = it6616_mipi_tx_read(mipi, 0xE5) & 0x0F;
2250*4882a593Smuzhiyun 		ulCNT = it6616_mipi_tx_read(mipi, 0xE4) + (ulCNT << 8);
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun 		sum += ulCNT;
2253*4882a593Smuzhiyun 	}
2254*4882a593Smuzhiyun 
2255*4882a593Smuzhiyun 	sum /= retry;
2256*4882a593Smuzhiyun 
2257*4882a593Smuzhiyun 	//PCLK = 13500*2048/sum;
2258*4882a593Smuzhiyun 	//PCLK = 27000*2048/sum;
2259*4882a593Smuzhiyun 	it6616->tx_pclk = it6616->tx_rclk * 2048 / sum;
2260*4882a593Smuzhiyun 	dev_dbg(dev, "mipi pclk = %u.%u MHz", it6616->tx_pclk / 1000,
2261*4882a593Smuzhiyun 		it6616->tx_pclk % 1000);
2262*4882a593Smuzhiyun }
2263*4882a593Smuzhiyun 
it6616_hdmi_rx_calc_rclk(struct it6616 * it6616)2264*4882a593Smuzhiyun static u32 it6616_hdmi_rx_calc_rclk(struct it6616 *it6616)
2265*4882a593Smuzhiyun {
2266*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2267*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2268*4882a593Smuzhiyun 	u32 rddata, rclk, sum = 0;
2269*4882a593Smuzhiyun 	int i, retry = 5;
2270*4882a593Smuzhiyun 	int t1usint;
2271*4882a593Smuzhiyun 	int t1usflt;
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun 	for (i = 0; i < retry; i++) {
2274*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x58, 0x80, 0x80);
2275*4882a593Smuzhiyun 		msleep(100);
2276*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x58, 0x80, 0x00);
2277*4882a593Smuzhiyun 
2278*4882a593Smuzhiyun 		rddata = it6616_hdmi_read(hdmi, 0x59);
2279*4882a593Smuzhiyun 		rddata += (it6616_hdmi_read(hdmi, 0x5A) << 8);
2280*4882a593Smuzhiyun 		rddata += (it6616_hdmi_read(hdmi, 0x5B) << 16);
2281*4882a593Smuzhiyun 
2282*4882a593Smuzhiyun 		sum += rddata;
2283*4882a593Smuzhiyun 	}
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	sum /= retry;
2286*4882a593Smuzhiyun 	rclk = sum / TIMER_100MS;
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 	dev_dbg(dev, "RCLK=%u KHz\n", rclk);
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	t1usint = rclk / 1000;
2291*4882a593Smuzhiyun 	t1usflt = (rclk / 1000 - t1usint) * 256;
2292*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x1E, 0x3F, t1usint & 0x3F);
2293*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x1F, t1usflt);
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	it6616->rclk = rclk;
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun 	return rclk;
2298*4882a593Smuzhiyun }
2299*4882a593Smuzhiyun 
it6616_hdmi_rx_calc_pclk(struct it6616 * it6616)2300*4882a593Smuzhiyun static u32 it6616_hdmi_rx_calc_pclk(struct it6616 *it6616)
2301*4882a593Smuzhiyun {
2302*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2303*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2304*4882a593Smuzhiyun 	u32 retry = 5, rddata, i;
2305*4882a593Smuzhiyun 	u32 pclk, sump = 0;
2306*4882a593Smuzhiyun 
2307*4882a593Smuzhiyun __recal:
2308*4882a593Smuzhiyun 	for (i = 0; i < retry; i++) {
2309*4882a593Smuzhiyun 		msleep(20);
2310*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x9A, BIT(7), 0x00);
2311*4882a593Smuzhiyun 		rddata = ((u32)(it6616_hdmi_read(hdmi, 0x9A) & 0x03) << 8) +
2312*4882a593Smuzhiyun 							it6616_hdmi_read(hdmi, 0x99);
2313*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x9A, BIT(7), BIT(7));
2314*4882a593Smuzhiyun 		sump += rddata;
2315*4882a593Smuzhiyun 	}
2316*4882a593Smuzhiyun 
2317*4882a593Smuzhiyun 	sump /= retry;
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun 	if (sump) {
2320*4882a593Smuzhiyun 		pclk = it6616->rclk * 512 / sump; // 512=2*256 because of 1T 2 pixel
2321*4882a593Smuzhiyun 		dev_dbg(dev, "PCLK = %u.%03u MHz", pclk / 1000, pclk % 1000);
2322*4882a593Smuzhiyun 		it6616->vinfo.pclk = pclk;
2323*4882a593Smuzhiyun 	} else {
2324*4882a593Smuzhiyun 		dev_err(dev, "%s: sump == 0", __func__);
2325*4882a593Smuzhiyun 		goto __recal;
2326*4882a593Smuzhiyun 	}
2327*4882a593Smuzhiyun 
2328*4882a593Smuzhiyun 	return pclk;
2329*4882a593Smuzhiyun }
2330*4882a593Smuzhiyun 
it6616_hdmi_rx_calc_tmds_clk(struct it6616 * it6616,u8 count)2331*4882a593Smuzhiyun static void it6616_hdmi_rx_calc_tmds_clk(struct it6616 *it6616, u8 count)
2332*4882a593Smuzhiyun {
2333*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2334*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2335*4882a593Smuzhiyun 	u32	sumt = 0;
2336*4882a593Smuzhiyun 	u8 rddata = 0, i;
2337*4882a593Smuzhiyun 
2338*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
2339*4882a593Smuzhiyun 		msleep(20);
2340*4882a593Smuzhiyun 		rddata = it6616_hdmi_read(hdmi, 0x48) + 1;
2341*4882a593Smuzhiyun 		sumt += rddata;
2342*4882a593Smuzhiyun 	}
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 	if (sumt) {
2345*4882a593Smuzhiyun 		rddata = it6616_hdmi_read(hdmi, 0x43) & 0xE0;
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 		if (rddata & BIT(7))
2348*4882a593Smuzhiyun 			it6616->vinfo.TMDSCLK = (it6616->rclk * (u32)1024 * i) / sumt;
2349*4882a593Smuzhiyun 		else if (rddata & BIT(6))
2350*4882a593Smuzhiyun 			it6616->vinfo.TMDSCLK = (it6616->rclk * (u32)512  * i) / sumt;
2351*4882a593Smuzhiyun 		else if (rddata & BIT(5))
2352*4882a593Smuzhiyun 			it6616->vinfo.TMDSCLK = (it6616->rclk * (u32)256  * i) / sumt;
2353*4882a593Smuzhiyun 		if (rddata == 0x00)
2354*4882a593Smuzhiyun 			it6616->vinfo.TMDSCLK = (it6616->rclk * (u32)128  * i) / sumt;
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun 		dev_dbg(dev, "TMDSCLK = %u.%03uMHz\n",
2357*4882a593Smuzhiyun 			it6616->vinfo.TMDSCLK / 1000, it6616->vinfo.TMDSCLK % 1000);
2358*4882a593Smuzhiyun 	} else {
2359*4882a593Smuzhiyun 		dev_err(dev, "%s - sumt==0\n", __func__);
2360*4882a593Smuzhiyun 	}
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun 
it6616_hdmi_receive_avi_infoframe_log(struct it6616 * it6616,u8 * buffer,size_t length)2363*4882a593Smuzhiyun static void it6616_hdmi_receive_avi_infoframe_log(struct it6616 *it6616, u8 *buffer, size_t length)
2364*4882a593Smuzhiyun {
2365*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2366*4882a593Smuzhiyun 	u8 i;
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 	dev_dbg(dev, "avi infoframe:");
2369*4882a593Smuzhiyun 	for (i = 0; i < length; i++)
2370*4882a593Smuzhiyun 		dev_err(dev, "0x%02x", buffer[i]);
2371*4882a593Smuzhiyun }
2372*4882a593Smuzhiyun 
it6616_hdmi_update_avi_infoframe(struct it6616 * it6616)2373*4882a593Smuzhiyun static int it6616_hdmi_update_avi_infoframe(struct it6616 *it6616)
2374*4882a593Smuzhiyun {
2375*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2376*4882a593Smuzhiyun 	struct hdmi_avi_infoframe *frame = &it6616->avi_if;
2377*4882a593Smuzhiyun 	u8 avi_packet[20] = { 0 };
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	avi_packet[0] = HDMI_INFOFRAME_TYPE_AVI;
2380*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 2);
2381*4882a593Smuzhiyun 	avi_packet[1] = it6616_hdmi_read(hdmi, REG_RX_AVI_HB1);// version
2382*4882a593Smuzhiyun 	avi_packet[2] = it6616_hdmi_read(hdmi, REG_RX_AVI_HB2);// version
2383*4882a593Smuzhiyun 	regmap_bulk_read(hdmi, REG_RX_AVI_DB0, &avi_packet[3], 16);
2384*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2385*4882a593Smuzhiyun 
2386*4882a593Smuzhiyun 	it6616_hdmi_receive_avi_infoframe_log(it6616, avi_packet, ARRAY_SIZE(avi_packet));
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 	return hdmi_infoframe_unpack((union hdmi_infoframe *)frame, avi_packet, sizeof(avi_packet));
2389*4882a593Smuzhiyun }
2390*4882a593Smuzhiyun 
it6616_hdmi_rx_setup_csc(struct it6616 * it6616)2391*4882a593Smuzhiyun static void it6616_hdmi_rx_setup_csc(struct it6616 *it6616)
2392*4882a593Smuzhiyun {
2393*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2394*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2395*4882a593Smuzhiyun 	enum hdmi_colorspace color_in;
2396*4882a593Smuzhiyun 	enum hdmi_colorspace color_out;
2397*4882a593Smuzhiyun 	enum csc_select csc_select;
2398*4882a593Smuzhiyun 	enum csc_matrix_type csc_matrix_type;
2399*4882a593Smuzhiyun 	u8 reg6b = 0;
2400*4882a593Smuzhiyun 	u8 reg6e = ((HDMI_RX_AUTO_CSC_SELECT << 7) |
2401*4882a593Smuzhiyun 			(HDMI_RX_QUANT_4LB << 6) |
2402*4882a593Smuzhiyun 			(HDMI_RX_CRCB_LIMIT << 5) |
2403*4882a593Smuzhiyun 			(HDMI_RX_COLOR_CLIP << 4) |
2404*4882a593Smuzhiyun 			(HDMI_RX_ENABLE_DITHER_FCNT_FUNCTION << 2) |
2405*4882a593Smuzhiyun 			(HDMI_RX_ENABLE_DITHER_FUNCTION << 1) |
2406*4882a593Smuzhiyun 			HDMI_RX_ENABLE_COLOR_UP_DN_FILTER);
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	color_in = it6616->avi_if.colorspace;
2409*4882a593Smuzhiyun 	color_out = it6616_hdmi_get_output_color_space(it6616);
2410*4882a593Smuzhiyun 
2411*4882a593Smuzhiyun 	if (color_in == HDMI_COLORSPACE_RGB && color_out != HDMI_COLORSPACE_RGB)
2412*4882a593Smuzhiyun 		csc_select = CSC_RGB2YUV;
2413*4882a593Smuzhiyun 	else if (color_in != HDMI_COLORSPACE_RGB && color_out == HDMI_COLORSPACE_RGB)
2414*4882a593Smuzhiyun 		csc_select = CSC_YUV2RGB;
2415*4882a593Smuzhiyun 	else
2416*4882a593Smuzhiyun 		csc_select = CSC_BYPASS;
2417*4882a593Smuzhiyun 
2418*4882a593Smuzhiyun 	switch (csc_select) {
2419*4882a593Smuzhiyun 	case CSC_RGB2YUV:
2420*4882a593Smuzhiyun 		dev_info(dev, "csc rgb2yuv");
2421*4882a593Smuzhiyun 		if (it6616->avi_if.colorimetry == HDMI_COLORIMETRY_ITU_709) {
2422*4882a593Smuzhiyun 			if (it6616->avi_if.quantization_range == HDMI_QUANTIZATION_RANGE_LIMITED)
2423*4882a593Smuzhiyun 				csc_matrix_type = CSCMtx_RGB2YUV_ITU709_16_235;
2424*4882a593Smuzhiyun 			else
2425*4882a593Smuzhiyun 				csc_matrix_type = CSCMtx_RGB2YUV_ITU709_00_255;
2426*4882a593Smuzhiyun 		} else {/* HDMI_COLORIMETRY_ITU_601 */
2427*4882a593Smuzhiyun 			if (it6616->avi_if.quantization_range == HDMI_QUANTIZATION_RANGE_LIMITED)
2428*4882a593Smuzhiyun 				csc_matrix_type = CSCMtx_RGB2YUV_ITU601_16_235;
2429*4882a593Smuzhiyun 			else
2430*4882a593Smuzhiyun 				csc_matrix_type = CSCMtx_RGB2YUV_ITU601_00_255;
2431*4882a593Smuzhiyun 		}
2432*4882a593Smuzhiyun 		break;
2433*4882a593Smuzhiyun 
2434*4882a593Smuzhiyun 	case CSC_YUV2RGB:
2435*4882a593Smuzhiyun 		dev_info(dev, "csc yuv2rgb");
2436*4882a593Smuzhiyun 
2437*4882a593Smuzhiyun 		if (it6616->avi_if.colorimetry == HDMI_COLORIMETRY_ITU_709)
2438*4882a593Smuzhiyun 			// when 709 format always to RGB full range
2439*4882a593Smuzhiyun 			csc_matrix_type = CSCMtx_YUV2RGB_ITU709_00_255;
2440*4882a593Smuzhiyun 		else if (it6616->avi_if.colorimetry == HDMI_COLORIMETRY_EXTENDED &&
2441*4882a593Smuzhiyun 			(it6616->avi_if.extended_colorimetry == 0x05 ||
2442*4882a593Smuzhiyun 			it6616->avi_if.extended_colorimetry == 0x06))
2443*4882a593Smuzhiyun 			// this Matrix is BT2020 YUV to BT2020 RGB, not normal limit/full range RGB
2444*4882a593Smuzhiyun 			csc_matrix_type = CSCMtx_YUV2RGB_BT2020_00_255; // for BT.2020 CSC
2445*4882a593Smuzhiyun 		else	/* Colormetry_ITU601 */
2446*4882a593Smuzhiyun 			csc_matrix_type = CSCMtx_YUV2RGB_ITU601_00_255;
2447*4882a593Smuzhiyun 		break;
2448*4882a593Smuzhiyun 
2449*4882a593Smuzhiyun 	case CSC_BYPASS:
2450*4882a593Smuzhiyun 		dev_info(dev, "csc byass");
2451*4882a593Smuzhiyun 		break;
2452*4882a593Smuzhiyun 	}
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun 	if (csc_select != CSC_BYPASS) {
2455*4882a593Smuzhiyun 		it6616_hdmi_chgbank(hdmi, 1);
2456*4882a593Smuzhiyun 		regmap_bulk_write(hdmi, 0x70, (u8 *)csc_matrix[csc_matrix_type],
2457*4882a593Smuzhiyun 						 sizeof(csc_matrix[0]));
2458*4882a593Smuzhiyun 		it6616_hdmi_chgbank(hdmi, 0);
2459*4882a593Smuzhiyun 	}
2460*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x6E, 0xF7, reg6e);
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x6C, 0x03, csc_select);
2463*4882a593Smuzhiyun 
2464*4882a593Smuzhiyun 	switch (color_in) {
2465*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV422:
2466*4882a593Smuzhiyun 		reg6b = 1 << 4;
2467*4882a593Smuzhiyun 		break;
2468*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV444:
2469*4882a593Smuzhiyun 		reg6b = 2 << 4;
2470*4882a593Smuzhiyun 		break;
2471*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV420:
2472*4882a593Smuzhiyun 		reg6b = 3 << 4;
2473*4882a593Smuzhiyun 		break;
2474*4882a593Smuzhiyun 	case HDMI_COLORSPACE_RGB:
2475*4882a593Smuzhiyun 		reg6b = 0 << 4;
2476*4882a593Smuzhiyun 		break;
2477*4882a593Smuzhiyun 	default:
2478*4882a593Smuzhiyun 		dev_err(dev, "## unknown input color space %x\n", color_in);
2479*4882a593Smuzhiyun 		break;
2480*4882a593Smuzhiyun 	}
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun 	switch (color_out) {
2483*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV422:
2484*4882a593Smuzhiyun 		reg6b |= 1 << 2;
2485*4882a593Smuzhiyun 		break;
2486*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV444:
2487*4882a593Smuzhiyun 		reg6b |= 2 << 2;
2488*4882a593Smuzhiyun 		break;
2489*4882a593Smuzhiyun 	case HDMI_COLORSPACE_YUV420:
2490*4882a593Smuzhiyun 		reg6b |= 3 << 2;
2491*4882a593Smuzhiyun 		break;
2492*4882a593Smuzhiyun 	case HDMI_COLORSPACE_RGB:
2493*4882a593Smuzhiyun 		reg6b |= 0 << 2;
2494*4882a593Smuzhiyun 		break;
2495*4882a593Smuzhiyun 	default:
2496*4882a593Smuzhiyun 		dev_err(dev, "## unknown output color space %x\n", color_out);
2497*4882a593Smuzhiyun 		break;
2498*4882a593Smuzhiyun 	}
2499*4882a593Smuzhiyun 
2500*4882a593Smuzhiyun 	if (it6616->mipi.bus_type == MIPI_CSI) {
2501*4882a593Smuzhiyun 		switch (it6616->mipi.data_type) {
2502*4882a593Smuzhiyun 		case CSI_RGB10b:
2503*4882a593Smuzhiyun 			reg6b |= 1 << 0;
2504*4882a593Smuzhiyun 			break;
2505*4882a593Smuzhiyun 		}
2506*4882a593Smuzhiyun 	} else {
2507*4882a593Smuzhiyun 		switch (it6616->mipi.data_type) {
2508*4882a593Smuzhiyun 		case DSI_RGB_36b:
2509*4882a593Smuzhiyun 			reg6b |= 2 << 0;
2510*4882a593Smuzhiyun 			break;
2511*4882a593Smuzhiyun 		case DSI_RGB_30b:
2512*4882a593Smuzhiyun 			reg6b |= 1 << 0;
2513*4882a593Smuzhiyun 			break;
2514*4882a593Smuzhiyun 		}
2515*4882a593Smuzhiyun 	}
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x6B, 0x3F, reg6b);
2518*4882a593Smuzhiyun }
2519*4882a593Smuzhiyun 
it6616_hdmi_rx_reset_audio_logic(struct it6616 * it6616)2520*4882a593Smuzhiyun static void it6616_hdmi_rx_reset_audio_logic(struct it6616 *it6616)
2521*4882a593Smuzhiyun {
2522*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2523*4882a593Smuzhiyun 	u8 temp;
2524*4882a593Smuzhiyun 
2525*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x22, BIT(1), BIT(1)); // audio reset
2526*4882a593Smuzhiyun 	msleep(20);
2527*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x22, BIT(1), 0x00);
2528*4882a593Smuzhiyun 
2529*4882a593Smuzhiyun 	// RegFS_Set[5:0] : Software set sampling frequency R/W
2530*4882a593Smuzhiyun 	temp = it6616_hdmi_read(hdmi, 0x8A);
2531*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x8A, temp);
2532*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x8A, temp);
2533*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x8A, temp);
2534*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x8A, temp);
2535*4882a593Smuzhiyun }
2536*4882a593Smuzhiyun 
it6616_hdmi_rx_audio_setup_i2s_justified(struct it6616 * it6616,u8 i2s_justified)2537*4882a593Smuzhiyun static void it6616_hdmi_rx_audio_setup_i2s_justified(struct it6616 *it6616, u8 i2s_justified)
2538*4882a593Smuzhiyun {
2539*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2540*4882a593Smuzhiyun 
2541*4882a593Smuzhiyun 	i2s_justified = (i2s_justified == FROM_CONFIG) ?
2542*4882a593Smuzhiyun 			it6616->audio_i2s_justified : i2s_justified;
2543*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x0F, 0x03, 0x00);
2544*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x82, 0x03, i2s_justified);
2545*4882a593Smuzhiyun }
2546*4882a593Smuzhiyun 
it6616_hdmi_tx_audio_setup(struct it6616 * it6616)2547*4882a593Smuzhiyun static void it6616_hdmi_tx_audio_setup(struct it6616 *it6616)
2548*4882a593Smuzhiyun {
2549*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2550*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2551*4882a593Smuzhiyun 	u32 sum = 0, cts_128;
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 	// RegForce_CTSMode : need to set to 1 for get the cts in the PKT,
2554*4882a593Smuzhiyun 	// 0 repersent nothing (HW using)
2555*4882a593Smuzhiyun 	// so set to 1 to get cts in the REG2C1/2C2/2C0
2556*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x86, BIT(0), BIT(0));
2557*4882a593Smuzhiyun 	it6616_hdmi_rx_audio_setup_i2s_justified(it6616, FROM_CONFIG);
2558*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 2);
2559*4882a593Smuzhiyun 	it6616->ainfo.n = ((u32)it6616_hdmi_read(hdmi, 0xBE) << 12) +
2560*4882a593Smuzhiyun 			((u32)it6616_hdmi_read(hdmi, 0xBF) << 4) +
2561*4882a593Smuzhiyun 			((u32)it6616_hdmi_read(hdmi, 0xC0) & 0x0F);
2562*4882a593Smuzhiyun 	it6616->ainfo.cts = it6616_hdmi_read(hdmi, 0xC0) >> 4;
2563*4882a593Smuzhiyun 	it6616->ainfo.cts |= ((u32)it6616_hdmi_read(hdmi, 0xC1)) << 12;
2564*4882a593Smuzhiyun 	it6616->ainfo.cts |= ((u32)it6616_hdmi_read(hdmi, 0xC2)) << 4;
2565*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2566*4882a593Smuzhiyun 
2567*4882a593Smuzhiyun 	if (it6616->ainfo.cts == 0) {
2568*4882a593Smuzhiyun 		dev_info(dev, "WARNING:cts = %u", it6616->ainfo.cts);
2569*4882a593Smuzhiyun 		return;
2570*4882a593Smuzhiyun 	}
2571*4882a593Smuzhiyun 
2572*4882a593Smuzhiyun 	// in the hdmi2.0 page 84, need bit 24, 25, 26, 27, 30, 31
2573*4882a593Smuzhiyun 	// Audio_CH_Status : Audio Channel status decoder value[31:24]
2574*4882a593Smuzhiyun 	// and bit[24:27] = Audio Sampling Rate
2575*4882a593Smuzhiyun 	it6616->ainfo.channel_status = ((it6616_hdmi_read(hdmi, 0xB5) & 0xC0) >> 2) +
2576*4882a593Smuzhiyun 					(it6616_hdmi_read(hdmi, 0xB5) & 0x0F);
2577*4882a593Smuzhiyun 	cts_128 = 128 * it6616->ainfo.cts;
2578*4882a593Smuzhiyun 	sum = it6616->ainfo.n * it6616->vinfo.TMDSCLK;
2579*4882a593Smuzhiyun 	it6616->ainfo.sample_freq = sum / cts_128;
2580*4882a593Smuzhiyun 
2581*4882a593Smuzhiyun 	dev_info(dev, "n = %u cts = %u\n", it6616->ainfo.n, it6616->ainfo.cts);
2582*4882a593Smuzhiyun 	dev_info(dev, "tmds clock = %d kHz\n", it6616->vinfo.TMDSCLK);
2583*4882a593Smuzhiyun 	dev_info(dev, "Audio_CH_Status[24:27 - 30:31][bit0~bit5] = 0x%02x\n",
2584*4882a593Smuzhiyun 		it6616->ainfo.channel_status);
2585*4882a593Smuzhiyun 	dev_info(dev, "sw clac sampling frequency = %d.%d kHz\n",
2586*4882a593Smuzhiyun 		it6616->ainfo.sample_freq, (sum % cts_128) * 100 / cts_128);
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun 	if (it6616->ainfo.sample_freq > 25 && it6616->ainfo.sample_freq <= 38)
2589*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_32K;
2590*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 38 && it6616->ainfo.sample_freq <= 45)
2591*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_44P1K;
2592*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 45 && it6616->ainfo.sample_freq <= 58)
2593*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_48K;
2594*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 58 && it6616->ainfo.sample_freq <= 78)
2595*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_64K;
2596*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 78 && it6616->ainfo.sample_freq <= 91)
2597*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_88P2K;
2598*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 91 && it6616->ainfo.sample_freq <= 106)
2599*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_96K;
2600*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 106 && it6616->ainfo.sample_freq <= 166)
2601*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_128K;
2602*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 166 && it6616->ainfo.sample_freq <= 182)
2603*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_176P4K;
2604*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 182 && it6616->ainfo.sample_freq <= 202)
2605*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_192K;
2606*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 224 && it6616->ainfo.sample_freq <= 320)
2607*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_256K;
2608*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 320 && it6616->ainfo.sample_freq <= 448)
2609*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_384K;
2610*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 448 && it6616->ainfo.sample_freq <= 638)
2611*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_512K;
2612*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 638 && it6616->ainfo.sample_freq <= 894)
2613*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_768K;
2614*4882a593Smuzhiyun 	else if (it6616->ainfo.sample_freq > 894 && it6616->ainfo.sample_freq <= 1324)
2615*4882a593Smuzhiyun 		it6616->ainfo.force_sample_freq = AUDIO_SAMPLING_1024K;
2616*4882a593Smuzhiyun 
2617*4882a593Smuzhiyun 	dev_info(dev, "Sampling_Frequency value 0x%02x", it6616->ainfo.force_sample_freq);
2618*4882a593Smuzhiyun 
2619*4882a593Smuzhiyun 	if (it6616->ainfo.channel_status == it6616->ainfo.force_sample_freq) {
2620*4882a593Smuzhiyun 		dev_dbg(dev, "channel_status == force_sample_freq\n");
2621*4882a593Smuzhiyun 		if (it6616_hdmi_read(hdmi, 0x81) & BIT(6)) {
2622*4882a593Smuzhiyun 			// RegForce_FS : 0: Disable Force Audio FS mode
2623*4882a593Smuzhiyun 			it6616_hdmi_set(hdmi, 0x81, BIT(6), 0x00);
2624*4882a593Smuzhiyun 			it6616_hdmi_rx_reset_audio_logic(it6616);
2625*4882a593Smuzhiyun 		}
2626*4882a593Smuzhiyun 		it6616->audio_sampling_freq_error_count = 0;
2627*4882a593Smuzhiyun 		return;
2628*4882a593Smuzhiyun 	}
2629*4882a593Smuzhiyun 
2630*4882a593Smuzhiyun 	it6616->audio_sampling_freq_error_count++;
2631*4882a593Smuzhiyun 	dev_dbg(dev, "it6616->audio_sampling_freq_error_count=%d\n",
2632*4882a593Smuzhiyun 		(int) it6616->audio_sampling_freq_error_count);
2633*4882a593Smuzhiyun 
2634*4882a593Smuzhiyun 	/* exceed max error count , enable Force Sampling Mode */
2635*4882a593Smuzhiyun 	if (it6616->audio_sampling_freq_error_count > MAX_AUDIO_SAMPLING_FREQ_ERROR_COUNT) {
2636*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x81, BIT(6), BIT(6));	// RegForce_FS : Force Audio FS mode
2637*4882a593Smuzhiyun 		// RegFS_Set[5:0] : Software set sampling frequency
2638*4882a593Smuzhiyun 		it6616_hdmi_set(hdmi, 0x8A, 0x3F, it6616->ainfo.force_sample_freq);
2639*4882a593Smuzhiyun 
2640*4882a593Smuzhiyun #if defined(Enable_Audio_Compatibility) && (Enable_Audio_Compatibility == 1)
2641*4882a593Smuzhiyun 		if (it6616->ainfo.sample_freq <= 182) {
2642*4882a593Smuzhiyun 			it6616_hdmi_set(hdmi, 0x89, 0x0C, 0x04);
2643*4882a593Smuzhiyun 			it6616_hdmi_set(hdmi, 0x86, 0x0C, 0x0C);
2644*4882a593Smuzhiyun 		} else {
2645*4882a593Smuzhiyun 			it6616_hdmi_set(hdmi, 0x89, 0x0C, 0x0C);
2646*4882a593Smuzhiyun 			it6616_hdmi_set(hdmi, 0x86, 0x0C, 0x04);
2647*4882a593Smuzhiyun 		}
2648*4882a593Smuzhiyun #endif
2649*4882a593Smuzhiyun 		it6616->audio_sampling_freq_error_count = 0;
2650*4882a593Smuzhiyun 		it6616_hdmi_rx_reset_audio_logic(it6616);
2651*4882a593Smuzhiyun 	}
2652*4882a593Smuzhiyun }
2653*4882a593Smuzhiyun 
it6616_hdmi_tx_audio_output_enable(struct it6616 * it6616,u8 output_interface)2654*4882a593Smuzhiyun static void it6616_hdmi_tx_audio_output_enable(struct it6616 *it6616, u8 output_interface)
2655*4882a593Smuzhiyun {
2656*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2657*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 1);
2660*4882a593Smuzhiyun 
2661*4882a593Smuzhiyun 	switch (output_interface) {
2662*4882a593Smuzhiyun 	case AUDIO_OFF:
2663*4882a593Smuzhiyun 		dev_info(dev, "audio off");
2664*4882a593Smuzhiyun 		it6616_hdmi_write(hdmi, 0xC7, 0x7F); // SPDIF/I2S tri-state on
2665*4882a593Smuzhiyun 		break;
2666*4882a593Smuzhiyun 
2667*4882a593Smuzhiyun 	case AUDIO_I2S:
2668*4882a593Smuzhiyun 	case AUDIO_SPDIF:
2669*4882a593Smuzhiyun 		dev_info(dev, "enable audio output");
2670*4882a593Smuzhiyun 		it6616_hdmi_write(hdmi, 0xC7, 0x00); // SPDIF/I2S tri-state off
2671*4882a593Smuzhiyun 		break;
2672*4882a593Smuzhiyun 	}
2673*4882a593Smuzhiyun 
2674*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2675*4882a593Smuzhiyun }
2676*4882a593Smuzhiyun 
it6616_hdmi_audio_mute_clear(struct it6616 * it6616)2677*4882a593Smuzhiyun static void it6616_hdmi_audio_mute_clear(struct it6616 *it6616)
2678*4882a593Smuzhiyun {
2679*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x8C, BIT(4), BIT(4)); // set RegHWMuteClr
2682*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x8C, BIT(4), 0x00); // clear RegHWMuteClr for clear H/W Mute
2683*4882a593Smuzhiyun }
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 
it6616_hdmi_rx_audio_process(struct it6616 * it6616)2686*4882a593Smuzhiyun static void it6616_hdmi_rx_audio_process(struct it6616 *it6616)
2687*4882a593Smuzhiyun {
2688*4882a593Smuzhiyun 	it6616_hdmi_tx_audio_output_enable(it6616, AUDIO_OFF);
2689*4882a593Smuzhiyun 	it6616_hdmi_rx_reset_audio_logic(it6616);
2690*4882a593Smuzhiyun 	it6616_hdmi_tx_audio_setup(it6616);
2691*4882a593Smuzhiyun 	it6616_hdmi_audio_mute_clear(it6616);
2692*4882a593Smuzhiyun 	it6616_hdmi_tx_audio_output_enable(it6616, it6616->audio_interface);
2693*4882a593Smuzhiyun }
2694*4882a593Smuzhiyun 
it6616_hdmi_initial(struct it6616 * it6616)2695*4882a593Smuzhiyun static void it6616_hdmi_initial(struct it6616 *it6616)
2696*4882a593Smuzhiyun {
2697*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2698*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2699*4882a593Smuzhiyun 
2700*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
2701*4882a593Smuzhiyun 	it6616_hdim_write_table(hdmi, it6616_hdmi_init_table);
2702*4882a593Smuzhiyun 
2703*4882a593Smuzhiyun 	it6616_hdmi_update_rs(it6616, DEFAULT_RS_LEVEL);
2704*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x67, BIT(7), it6616->hdmi_rx_disable_pixel_repeat << 7);
2705*4882a593Smuzhiyun 	it6616_hdmi_set(hdmi, 0x69, BIT(6) | BIT(5),
2706*4882a593Smuzhiyun 			it6616->hdmi_rx_video_stable_condition << 5);
2707*4882a593Smuzhiyun 	dev_dbg(dev,
2708*4882a593Smuzhiyun 		"set hdmi rx video stable condition, reg0x69[6:5], 0x%02x",
2709*4882a593Smuzhiyun 		it6616_hdmi_read(hdmi, 0x69));
2710*4882a593Smuzhiyun }
2711*4882a593Smuzhiyun 
it6616_hdmi_irq_color_depth(struct it6616 * it6616)2712*4882a593Smuzhiyun static void it6616_hdmi_irq_color_depth(struct it6616 *it6616)
2713*4882a593Smuzhiyun {
2714*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2715*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2716*4882a593Smuzhiyun 	u8 input_color_depth;
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun 	input_color_depth = (it6616_hdmi_read(hdmi, 0x98) >> 4) & 0x0F;
2719*4882a593Smuzhiyun 	dev_dbg(dev, "input color depth = %d bits\n", input_color_depth * 6);
2720*4882a593Smuzhiyun }
2721*4882a593Smuzhiyun 
it6616_hdmi_irq_new_avi_infoframe(struct it6616 * it6616)2722*4882a593Smuzhiyun static void it6616_hdmi_irq_new_avi_infoframe(struct it6616 *it6616)
2723*4882a593Smuzhiyun {
2724*4882a593Smuzhiyun 	struct hdmi_avi_infoframe *avi_new;
2725*4882a593Smuzhiyun 	struct hdmi_avi_infoframe *avi_prev;
2726*4882a593Smuzhiyun 
2727*4882a593Smuzhiyun 	if (it6616_hdmi_update_avi_infoframe(it6616) == 0) {
2728*4882a593Smuzhiyun 		avi_new = &it6616->avi_if;
2729*4882a593Smuzhiyun 		avi_prev = &it6616->avi_if_prev;
2730*4882a593Smuzhiyun 		hdmi_infoframe_log(KERN_INFO, &it6616->hdmi_i2c->dev,
2731*4882a593Smuzhiyun 					(union hdmi_infoframe *)avi_new);
2732*4882a593Smuzhiyun 
2733*4882a593Smuzhiyun 		if (avi_prev->video_code != avi_new->video_code)
2734*4882a593Smuzhiyun 			avi_prev->video_code = avi_new->video_code;
2735*4882a593Smuzhiyun 		if (avi_prev->colorspace != avi_new->colorspace)
2736*4882a593Smuzhiyun 			avi_prev->colorspace = avi_new->colorspace;
2737*4882a593Smuzhiyun 	}
2738*4882a593Smuzhiyun }
2739*4882a593Smuzhiyun 
it6616_hdmi_hpd_trun_on(struct it6616 * it6616)2740*4882a593Smuzhiyun static void it6616_hdmi_hpd_trun_on(struct it6616 *it6616)
2741*4882a593Smuzhiyun {
2742*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_enable(it6616, 1);
2743*4882a593Smuzhiyun 	it6616_hdmi_video_reset(it6616);
2744*4882a593Smuzhiyun 	it6616_hdmi_rx_reset_audio_logic(it6616);
2745*4882a593Smuzhiyun 	it6616_hdmi_hpd_output(it6616, true);
2746*4882a593Smuzhiyun }
2747*4882a593Smuzhiyun 
it6616_hdmi_hpd_trun_off(struct it6616 * it6616)2748*4882a593Smuzhiyun static void it6616_hdmi_hpd_trun_off(struct it6616 *it6616)
2749*4882a593Smuzhiyun {
2750*4882a593Smuzhiyun 	it6616_hdmi_hpd_output(it6616, false);
2751*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_enable(it6616, 0);
2752*4882a593Smuzhiyun }
2753*4882a593Smuzhiyun 
it6616_mipitx_irq(struct it6616 * it6616)2754*4882a593Smuzhiyun static void it6616_mipitx_irq(struct it6616 *it6616)
2755*4882a593Smuzhiyun {
2756*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
2757*4882a593Smuzhiyun 	struct device *dev = &it6616->mipi_i2c->dev;
2758*4882a593Smuzhiyun 	u8 reg09h, reg0ah, reg0bh;
2759*4882a593Smuzhiyun 
2760*4882a593Smuzhiyun 	reg09h = it6616_mipi_tx_read(mipi, 0x09);
2761*4882a593Smuzhiyun 	reg0ah = it6616_mipi_tx_read(mipi, 0x0A);
2762*4882a593Smuzhiyun 	reg0bh = it6616_mipi_tx_read(mipi, 0x0B);
2763*4882a593Smuzhiyun 
2764*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x0A, reg0ah);
2765*4882a593Smuzhiyun 	it6616_mipi_tx_write(mipi, 0x0B, reg0bh);
2766*4882a593Smuzhiyun 
2767*4882a593Smuzhiyun 	if (reg0bh & 0x10) {
2768*4882a593Smuzhiyun 		it6616->mipi_tx_video_stable = it6616_mipi_tx_get_video_stable(it6616);
2769*4882a593Smuzhiyun 		dev_info(dev, "mipi tx Video Stable Change ...");
2770*4882a593Smuzhiyun 		dev_info(dev, "mipi tx reg09 = 0x%02x, video %sstable",
2771*4882a593Smuzhiyun 			reg09h, it6616->mipi_tx_video_stable ? "" : "un");
2772*4882a593Smuzhiyun 
2773*4882a593Smuzhiyun 		if (it6616->mipi_tx_video_stable) {
2774*4882a593Smuzhiyun 			it6616_mipi_tx_calc_rclk(it6616);
2775*4882a593Smuzhiyun 			it6616_mipi_tx_calc_mclk(it6616);
2776*4882a593Smuzhiyun 			it6616_mipi_tx_calc_pclk(it6616);
2777*4882a593Smuzhiyun 		}
2778*4882a593Smuzhiyun 	}
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	if (reg0ah & 0x70) {
2781*4882a593Smuzhiyun 		if (reg0ah & 0x20)
2782*4882a593Smuzhiyun 			dev_err(dev, "Mipi Byte mismatch Err!!!\n");
2783*4882a593Smuzhiyun 		if (reg0ah & 0x40)
2784*4882a593Smuzhiyun 			dev_err(dev, "mipi P2M FIFO Err!!!\n");
2785*4882a593Smuzhiyun 	}
2786*4882a593Smuzhiyun }
2787*4882a593Smuzhiyun 
it6616_hdmi_irq(struct it6616 * it6616)2788*4882a593Smuzhiyun static void it6616_hdmi_irq(struct it6616 *it6616)
2789*4882a593Smuzhiyun {
2790*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
2791*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun 	u8 reg05h, reg06h, Reg08h, Reg09h;
2794*4882a593Smuzhiyun 	u8 Reg10h, Reg11h, Reg12h;
2795*4882a593Smuzhiyun 	u8 Reg13h, Reg14h, Reg15h;
2796*4882a593Smuzhiyun 	u8 Reg1Ah, Reg1Bh;
2797*4882a593Smuzhiyun 
2798*4882a593Smuzhiyun 	reg05h = it6616_hdmi_read(hdmi, 0x05);
2799*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x05, reg05h);
2800*4882a593Smuzhiyun 	reg06h = it6616_hdmi_read(hdmi, 0x06);
2801*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x06, reg06h);
2802*4882a593Smuzhiyun 	Reg08h = it6616_hdmi_read(hdmi, 0x08);
2803*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x08, Reg08h);
2804*4882a593Smuzhiyun 	Reg09h = it6616_hdmi_read(hdmi, 0x09);
2805*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x09, Reg09h);
2806*4882a593Smuzhiyun 
2807*4882a593Smuzhiyun 	Reg10h = it6616_hdmi_read(hdmi, 0x10);
2808*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x10, Reg10h);
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun 	Reg11h = it6616_hdmi_read(hdmi, 0x11);
2811*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x11, Reg11h);
2812*4882a593Smuzhiyun 
2813*4882a593Smuzhiyun 	Reg12h = it6616_hdmi_read(hdmi, 0x12);
2814*4882a593Smuzhiyun 	it6616_hdmi_write(hdmi, 0x12, Reg12h & 0x7F);
2815*4882a593Smuzhiyun 
2816*4882a593Smuzhiyun 	Reg13h = it6616_hdmi_read(hdmi, 0x13);
2817*4882a593Smuzhiyun 	Reg14h = it6616_hdmi_read(hdmi, 0x14);
2818*4882a593Smuzhiyun 	Reg15h = it6616_hdmi_read(hdmi, 0x15);
2819*4882a593Smuzhiyun 
2820*4882a593Smuzhiyun 	if (reg05h != 0x00) {
2821*4882a593Smuzhiyun 		if (reg05h & 0x10)
2822*4882a593Smuzhiyun 			dev_info(dev, "# hdmi mode chg #\n");
2823*4882a593Smuzhiyun 		if (reg05h & 0x20) {
2824*4882a593Smuzhiyun 			dev_err(dev, "# ECC Error #\n");
2825*4882a593Smuzhiyun 			it6616_hdmi_hdcp_reset(it6616);
2826*4882a593Smuzhiyun 		}
2827*4882a593Smuzhiyun 		if (reg05h & 0x40)
2828*4882a593Smuzhiyun 			dev_err(dev, "# Deskew Error #\n");
2829*4882a593Smuzhiyun 		if (reg05h & 0x80)
2830*4882a593Smuzhiyun 			dev_err(dev, "# H2VSkew Fail #\n");
2831*4882a593Smuzhiyun 		if (reg05h & 0x04) {
2832*4882a593Smuzhiyun 			dev_info(dev, "# Input Clock Change Detect #\n");
2833*4882a593Smuzhiyun 			if (it6616_hdmi_is_clock_stable(it6616))
2834*4882a593Smuzhiyun 				dev_info(dev, "# Clock Stable #\n");
2835*4882a593Smuzhiyun 			else
2836*4882a593Smuzhiyun 				dev_err(dev, "# Clock NOT Stable #\n");
2837*4882a593Smuzhiyun 		}
2838*4882a593Smuzhiyun 
2839*4882a593Smuzhiyun 		if (reg05h & 0x02)
2840*4882a593Smuzhiyun 			dev_info(dev, "# Rx CKOn Detect #\n");
2841*4882a593Smuzhiyun 
2842*4882a593Smuzhiyun 		if (reg05h & 0x01) {
2843*4882a593Smuzhiyun 			dev_info(dev, "# 5V state change INT #\n");
2844*4882a593Smuzhiyun 			it6616_hdmi_hdcp_reset(it6616);
2845*4882a593Smuzhiyun 			if (it6616_hdmi_is_5v_on(it6616))
2846*4882a593Smuzhiyun 				it6616_hdmi_hpd_trun_on(it6616);
2847*4882a593Smuzhiyun 			else
2848*4882a593Smuzhiyun 				it6616_hdmi_hpd_trun_off(it6616);
2849*4882a593Smuzhiyun 		}
2850*4882a593Smuzhiyun 	}
2851*4882a593Smuzhiyun 
2852*4882a593Smuzhiyun 	if (reg06h != 0x00) {
2853*4882a593Smuzhiyun 		if (reg06h & 0x80)
2854*4882a593Smuzhiyun 			dev_err(dev, "# FSM Error  #\n");
2855*4882a593Smuzhiyun 		if (reg06h & 0x40)
2856*4882a593Smuzhiyun 			dev_err(dev, "# CH2 Symbol lock Rst #\n");
2857*4882a593Smuzhiyun 		if (reg06h & 0x20)
2858*4882a593Smuzhiyun 			dev_err(dev, "# CH1 Symbol lock Rst #\n");
2859*4882a593Smuzhiyun 		if (reg06h & 0x10)
2860*4882a593Smuzhiyun 			dev_err(dev, "# CH0 Symbol lock Rst #\n");
2861*4882a593Smuzhiyun 		if (reg06h & 0x08)
2862*4882a593Smuzhiyun 			dev_err(dev, "# CH2 CDR FIFO Aut0-Rst #\n");
2863*4882a593Smuzhiyun 		if (reg06h & 0x04)
2864*4882a593Smuzhiyun 			dev_err(dev, "# CH1 CDR FIFO Aut0-Rst #\n");
2865*4882a593Smuzhiyun 		if (reg06h & 0x02)
2866*4882a593Smuzhiyun 			dev_err(dev, "# CH0 CDR FIFO Aut0-Rst #\n");
2867*4882a593Smuzhiyun 		if (reg06h & 0x01)
2868*4882a593Smuzhiyun 			dev_info(dev, "# Symbol Lock State Change # ");
2869*4882a593Smuzhiyun 	}
2870*4882a593Smuzhiyun 
2871*4882a593Smuzhiyun 	if (Reg09h != 0x00) {
2872*4882a593Smuzhiyun 		if (Reg09h & 0x01)
2873*4882a593Smuzhiyun 			dev_info(dev, "# HDCP Authentication Start #");
2874*4882a593Smuzhiyun 		if (Reg09h & 0x02) {
2875*4882a593Smuzhiyun 			dev_info(dev, "# HDCP Authentication Done #");
2876*4882a593Smuzhiyun 			it6616->hdmi_rx_hdcp_state = true;
2877*4882a593Smuzhiyun 		}
2878*4882a593Smuzhiyun 		if (Reg09h & 0x04) {
2879*4882a593Smuzhiyun 			it6616->hdmi_rx_hdcp_state = it6616_get_hdcp_status(it6616);
2880*4882a593Smuzhiyun 			dev_info(dev, "HDCP Encryption change interrupt!");
2881*4882a593Smuzhiyun 			dev_info(dev, "HDCP Encryption %s!",
2882*4882a593Smuzhiyun 				it6616->hdmi_rx_hdcp_state ? "ON" : "OFF");
2883*4882a593Smuzhiyun 		}
2884*4882a593Smuzhiyun 		if (Reg09h & 0x08) {
2885*4882a593Smuzhiyun 			dev_info(dev, "# HDCP Off #");
2886*4882a593Smuzhiyun 			it6616->hdmi_rx_hdcp_state = false;
2887*4882a593Smuzhiyun 		}
2888*4882a593Smuzhiyun 	}
2889*4882a593Smuzhiyun 
2890*4882a593Smuzhiyun 	if (Reg12h != 0x00) {
2891*4882a593Smuzhiyun 		if (Reg12h & BIT(7)) {
2892*4882a593Smuzhiyun 			Reg1Ah = it6616_hdmi_read(hdmi, 0x1A);
2893*4882a593Smuzhiyun 			Reg1Bh = it6616_hdmi_read(hdmi, 0x1B) & 0x07;
2894*4882a593Smuzhiyun 			dev_info(dev, "# Video Parameters Change #\n");
2895*4882a593Smuzhiyun 			dev_info(dev, "# VidParaChange_Sts=Reg1Bh=0x%02X Reg1Ah=0x%02X\n",
2896*4882a593Smuzhiyun 				(int) Reg1Bh, (int) Reg1Ah);
2897*4882a593Smuzhiyun 			it6616_hdmi_rx_calc_tmds_clk(it6616, 5);
2898*4882a593Smuzhiyun 			it6616_hdmi_rx_calc_pclk(it6616);
2899*4882a593Smuzhiyun 			it6616_hdmi_rx_get_video_info(it6616);
2900*4882a593Smuzhiyun 			// only parameter change need to clear INT here ,
2901*4882a593Smuzhiyun 			//or register 1A/1B can't be read after clear.
2902*4882a593Smuzhiyun 			it6616_hdmi_write(hdmi, 0x12, 0x80);
2903*4882a593Smuzhiyun 		}
2904*4882a593Smuzhiyun 
2905*4882a593Smuzhiyun 		if (Reg12h & BIT(6))
2906*4882a593Smuzhiyun 			dev_info(dev, "# 3D audio Valie Change #\n");
2907*4882a593Smuzhiyun 		if (Reg12h & BIT(5))
2908*4882a593Smuzhiyun 			dev_info(dev, "# DRM pkt Change #\n");
2909*4882a593Smuzhiyun 		if (Reg12h & 0x10)
2910*4882a593Smuzhiyun 			dev_info(dev, "# New Audio PKT Received #\n");
2911*4882a593Smuzhiyun 		if (Reg12h & 0x08)
2912*4882a593Smuzhiyun 			dev_info(dev, "# New ACP PKT Received #\n");
2913*4882a593Smuzhiyun 		if (Reg12h & 0x04)
2914*4882a593Smuzhiyun 			dev_info(dev, "# New SPD PKT Received #\n");
2915*4882a593Smuzhiyun 		if (Reg12h & 0x02)
2916*4882a593Smuzhiyun 			dev_info(dev, "# New MPEG InfoFrame Received #\n");
2917*4882a593Smuzhiyun 		if (Reg12h & 0x01) {
2918*4882a593Smuzhiyun 			dev_info(dev, "# New AVI InfoFrame Received #\n");
2919*4882a593Smuzhiyun 			it6616_hdmi_irq_new_avi_infoframe(it6616);
2920*4882a593Smuzhiyun 			it6616_hdmi_rx_setup_csc(it6616);
2921*4882a593Smuzhiyun 		}
2922*4882a593Smuzhiyun 	}
2923*4882a593Smuzhiyun 
2924*4882a593Smuzhiyun 	if (Reg10h != 0x00) {
2925*4882a593Smuzhiyun 		if (Reg10h & 0x80) {
2926*4882a593Smuzhiyun 			dev_err(dev, "# Audio FIFO Error #");
2927*4882a593Smuzhiyun 			it6616_hdmi_rx_audio_process(it6616);
2928*4882a593Smuzhiyun 		}
2929*4882a593Smuzhiyun 		if (Reg10h & 0x40)
2930*4882a593Smuzhiyun 			dev_info(dev, "# Audio Auto Mute #");
2931*4882a593Smuzhiyun 		// todo: how about on/off flag at the same time ?
2932*4882a593Smuzhiyun 		if ((Reg10h & 0x20)) {
2933*4882a593Smuzhiyun 			dev_info(dev, "# PKT Left Mute #");
2934*4882a593Smuzhiyun 			it6616_hdmi_rx_set_av_mute(it6616, AV_MUTE_OFF);
2935*4882a593Smuzhiyun 		}
2936*4882a593Smuzhiyun 		if ((Reg10h & 0x10)) {
2937*4882a593Smuzhiyun 			dev_info(dev, "# Set Mute PKT Received #");
2938*4882a593Smuzhiyun 			it6616_hdmi_rx_set_av_mute(it6616, AV_MUTE_ON);
2939*4882a593Smuzhiyun 		}
2940*4882a593Smuzhiyun 		if (Reg10h & 0x08)
2941*4882a593Smuzhiyun 			dev_info(dev, "# Timer Counter Interrupt #");
2942*4882a593Smuzhiyun 		if (Reg10h & 0x04)
2943*4882a593Smuzhiyun 			dev_info(dev, "# Video Mode Changed #");
2944*4882a593Smuzhiyun 		if (Reg10h & 0x02) {
2945*4882a593Smuzhiyun 			it6616->hdmi_rx_video_stable = it6616_hdmi_is_scdt_on(it6616);
2946*4882a593Smuzhiyun 			dev_info(dev, "SCDT %s", it6616->hdmi_rx_video_stable ? "ON" : "OFF");
2947*4882a593Smuzhiyun 
2948*4882a593Smuzhiyun 			if (it6616->hdmi_rx_video_stable) {
2949*4882a593Smuzhiyun 				it6616_hdmi_rx_calc_tmds_clk(it6616, 5);
2950*4882a593Smuzhiyun 				it6616_hdmi_rx_calc_pclk(it6616);
2951*4882a593Smuzhiyun 				it6616_hdmi_rx_get_video_info(it6616);
2952*4882a593Smuzhiyun 				it6616_hdmi_rx_audio_process(it6616);
2953*4882a593Smuzhiyun 				msleep(400);
2954*4882a593Smuzhiyun 				it6616_mipi_tx_get_support_format(it6616);
2955*4882a593Smuzhiyun 				it6616_enable_mipi(it6616);
2956*4882a593Smuzhiyun 			} else {
2957*4882a593Smuzhiyun 				it6616_disable_mipi(it6616);
2958*4882a593Smuzhiyun 			}
2959*4882a593Smuzhiyun 		}
2960*4882a593Smuzhiyun 		if (Reg10h & 0x01)
2961*4882a593Smuzhiyun 			dev_info(dev, "# Video Abnormal Interrupt #\n");
2962*4882a593Smuzhiyun 	}
2963*4882a593Smuzhiyun 
2964*4882a593Smuzhiyun 	if (Reg11h != 0x00) {
2965*4882a593Smuzhiyun 		if (Reg11h & BIT(5))
2966*4882a593Smuzhiyun 			dev_info(dev, "# No Audio InfoFrame Received #\n");
2967*4882a593Smuzhiyun 		if (Reg11h & BIT(4))
2968*4882a593Smuzhiyun 			dev_info(dev, "# No AVI InfoFrame Received #\n");
2969*4882a593Smuzhiyun 		if (Reg11h & BIT(3)) {
2970*4882a593Smuzhiyun 			dev_info(dev, "# CD Detect #\n");
2971*4882a593Smuzhiyun 			it6616_hdmi_irq_color_depth(it6616);
2972*4882a593Smuzhiyun 		}
2973*4882a593Smuzhiyun 		if (Reg11h & BIT(1))
2974*4882a593Smuzhiyun 			it6616_hdmi_write(hdmi, 0x11, BIT(1));
2975*4882a593Smuzhiyun 		if (Reg11h & BIT(0))
2976*4882a593Smuzhiyun 			it6616_hdmi_write(hdmi, 0x11, BIT(0));
2977*4882a593Smuzhiyun 	}
2978*4882a593Smuzhiyun 
2979*4882a593Smuzhiyun 	if (Reg13h != 0x00) {
2980*4882a593Smuzhiyun 		if (Reg13h & BIT(0))
2981*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 power 5V detect #\n");
2982*4882a593Smuzhiyun 		if (Reg13h & BIT(1))
2983*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 HDMI mode #\n");
2984*4882a593Smuzhiyun 		else
2985*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 DVI mode #\n");
2986*4882a593Smuzhiyun 	}
2987*4882a593Smuzhiyun 
2988*4882a593Smuzhiyun 	if (Reg14h != 0x00) {
2989*4882a593Smuzhiyun 		if (Reg14h & BIT(0))
2990*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 IPLL clock is higher than 100MHz #\n");
2991*4882a593Smuzhiyun 	}
2992*4882a593Smuzhiyun 
2993*4882a593Smuzhiyun 	if (Reg15h != 0x00) {
2994*4882a593Smuzhiyun 		if (Reg15h & BIT(6))
2995*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 EDID Idle #\n");
2996*4882a593Smuzhiyun 		else
2997*4882a593Smuzhiyun 			dev_dbg(dev, "# Port 0 EDID active #\n");
2998*4882a593Smuzhiyun 	}
2999*4882a593Smuzhiyun }
3000*4882a593Smuzhiyun 
it6616_get_chip_id(struct it6616 * it6616)3001*4882a593Smuzhiyun static int it6616_get_chip_id(struct it6616 *it6616)
3002*4882a593Smuzhiyun {
3003*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
3004*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
3005*4882a593Smuzhiyun 	u8 chip_id[4] = {0x54, 0x49, 0x16, 0x66};
3006*4882a593Smuzhiyun 	int i, ret;
3007*4882a593Smuzhiyun 
3008*4882a593Smuzhiyun 	for (i = 0; i < sizeof(chip_id); i++) {
3009*4882a593Smuzhiyun 		ret = it6616_hdmi_read(hdmi, i);
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 		if (ret != chip_id[i]) {
3012*4882a593Smuzhiyun 			dev_err(dev, "not 6616 reg[0x%02x]=0x%02x", i, ret);
3013*4882a593Smuzhiyun 			return -ENODEV;
3014*4882a593Smuzhiyun 		}
3015*4882a593Smuzhiyun 	}
3016*4882a593Smuzhiyun 
3017*4882a593Smuzhiyun 	return 0;
3018*4882a593Smuzhiyun }
3019*4882a593Smuzhiyun 
it6616_poll_threaded_handler(struct it6616 * it6616)3020*4882a593Smuzhiyun static void it6616_poll_threaded_handler(struct it6616 *it6616)
3021*4882a593Smuzhiyun {
3022*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
3023*4882a593Smuzhiyun 	enum av_mute_state mute_state_config = !!(it6616_hdmi_read(hdmi, 0x4F) & BIT(5));
3024*4882a593Smuzhiyun 	enum av_mute_state current_mute_state;
3025*4882a593Smuzhiyun 
3026*4882a593Smuzhiyun 	current_mute_state = it6616_hdmi_rx_get_av_mute_state(it6616);
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 	if (mute_state_config != current_mute_state)
3029*4882a593Smuzhiyun 		it6616_hdmi_rx_set_av_mute(it6616, current_mute_state);
3030*4882a593Smuzhiyun }
3031*4882a593Smuzhiyun 
it6616_intp_threaded_handler(int unused,void * data)3032*4882a593Smuzhiyun static irqreturn_t it6616_intp_threaded_handler(int unused, void *data)
3033*4882a593Smuzhiyun {
3034*4882a593Smuzhiyun 	struct it6616 *it6616 = (struct it6616 *)data;
3035*4882a593Smuzhiyun 
3036*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3037*4882a593Smuzhiyun 
3038*4882a593Smuzhiyun 	it6616_hdmi_irq(it6616);
3039*4882a593Smuzhiyun 	it6616_mipitx_irq(it6616);
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 	return IRQ_HANDLED;
3044*4882a593Smuzhiyun }
3045*4882a593Smuzhiyun 
it6616_initial(struct it6616 * it6616)3046*4882a593Smuzhiyun static int it6616_initial(struct it6616 *it6616)
3047*4882a593Smuzhiyun {
3048*4882a593Smuzhiyun 	struct device *dev = &it6616->hdmi_i2c->dev;
3049*4882a593Smuzhiyun 
3050*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3051*4882a593Smuzhiyun 
3052*4882a593Smuzhiyun 	/* get device id */
3053*4882a593Smuzhiyun 	if (it6616_get_chip_id(it6616)) {
3054*4882a593Smuzhiyun 		dev_err(dev, "can not find it6616");
3055*4882a593Smuzhiyun 		return -ENODEV;
3056*4882a593Smuzhiyun 	}
3057*4882a593Smuzhiyun 
3058*4882a593Smuzhiyun 	// init driver variables:
3059*4882a593Smuzhiyun 	it6616->edid_len = sizeof(default_edid);
3060*4882a593Smuzhiyun 	memcpy(it6616->edid_data, default_edid, it6616->edid_len);
3061*4882a593Smuzhiyun 
3062*4882a593Smuzhiyun 	// mipi common settings:
3063*4882a593Smuzhiyun 	it6616->mipi.bus_type = MIPI_TX_INTERFACE;
3064*4882a593Smuzhiyun 	it6616->mipi.lane_cnt = it6616->csi_lanes_in_use;
3065*4882a593Smuzhiyun 	it6616->mipi.data_type = MIPI_TX_DATA_TYPE;
3066*4882a593Smuzhiyun 
3067*4882a593Smuzhiyun 	it6616->mipi_tx_enable_auto_adjust_lane_count =
3068*4882a593Smuzhiyun 			MIPI_TX_ENABLE_AUTO_ADJUST_LANE_COUNT;
3069*4882a593Smuzhiyun 	it6616->mipi_tx_enable_h_fire_packet =
3070*4882a593Smuzhiyun 			MIPI_TX_ENABLE_H_FIRE_PACKET;
3071*4882a593Smuzhiyun 	it6616->mipi_tx_enable_initial_fire_lp_cmd =
3072*4882a593Smuzhiyun 			MIPI_TX_ENABLE_INITIAL_FIRE_LP_CMD;
3073*4882a593Smuzhiyun 	// hdmi settings:
3074*4882a593Smuzhiyun 	it6616->rs_level = DEFAULT_RS_LEVEL;
3075*4882a593Smuzhiyun 	it6616->audio_interface = AUDIO_I2S;
3076*4882a593Smuzhiyun 	it6616->audio_i2s_justified = AUDIO_I2S_JUSTIFIED;
3077*4882a593Smuzhiyun 	it6616->hdmi_rx_disable_pixel_repeat =
3078*4882a593Smuzhiyun 				HDMI_RX_DISABLE_PIXEL_REPEAT;
3079*4882a593Smuzhiyun 	it6616->hdmi_rx_video_stable_condition =
3080*4882a593Smuzhiyun 				HDMI_RX_VIDEO_STABLE_CONDITION;
3081*4882a593Smuzhiyun 	it6616->mipi_tx_enable_continuous_clock =
3082*4882a593Smuzhiyun 				MIPI_TX_ENABLE_CONTINUOUS_CLOCK;
3083*4882a593Smuzhiyun 	it6616->mipi_tx_enable_manual_adjusted_d_phy =
3084*4882a593Smuzhiyun 				MIPI_TX_ENABLE_MANUAL_ADJUSTED_D_PHY;
3085*4882a593Smuzhiyun 	it6616->hdmi_rx_video_stable = false;
3086*4882a593Smuzhiyun 	it6616->mipi_tx_video_stable = false;
3087*4882a593Smuzhiyun 	it6616->hdmi_rx_hdcp_state = false;
3088*4882a593Smuzhiyun 	it6616->mipi_tx_enable_mipi_output = false;
3089*4882a593Smuzhiyun 
3090*4882a593Smuzhiyun 	it6616_hdmi_rx_calc_rclk(it6616);
3091*4882a593Smuzhiyun 
3092*4882a593Smuzhiyun 	it6616_hdmi_initial(it6616);
3093*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_init(it6616);
3094*4882a593Smuzhiyun 	it6616_mipitx_init_bus_para(it6616);
3095*4882a593Smuzhiyun 	it6616_mipitx_initial(it6616);
3096*4882a593Smuzhiyun 
3097*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3098*4882a593Smuzhiyun 
3099*4882a593Smuzhiyun 	return 0;
3100*4882a593Smuzhiyun }
3101*4882a593Smuzhiyun 
it6616_set_hpd(struct it6616 * it6616,u8 hpd)3102*4882a593Smuzhiyun static __maybe_unused void it6616_set_hpd(struct it6616 *it6616, u8 hpd)
3103*4882a593Smuzhiyun {
3104*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3105*4882a593Smuzhiyun 
3106*4882a593Smuzhiyun 	if (hpd)
3107*4882a593Smuzhiyun 		it6616_hdmi_hpd_trun_on(it6616);
3108*4882a593Smuzhiyun 	else
3109*4882a593Smuzhiyun 		it6616_hdmi_hpd_trun_off(it6616);
3110*4882a593Smuzhiyun 
3111*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3112*4882a593Smuzhiyun }
3113*4882a593Smuzhiyun 
it6616_update_edid_data(struct it6616 * it6616,u8 * edid,int edid_len)3114*4882a593Smuzhiyun static __maybe_unused void it6616_update_edid_data(struct it6616 *it6616, u8 *edid, int edid_len)
3115*4882a593Smuzhiyun {
3116*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3117*4882a593Smuzhiyun 
3118*4882a593Smuzhiyun 	memcpy(it6616->edid_data, edid, it6616->edid_len);
3119*4882a593Smuzhiyun 	it6616->edid_len = edid_len;
3120*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_init(it6616);
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3123*4882a593Smuzhiyun }
3124*4882a593Smuzhiyun 
3125*4882a593Smuzhiyun static const struct regmap_range it6616_hdmi_volatile_ranges[] = {
3126*4882a593Smuzhiyun 	{ .range_min = 0, .range_max = 0xff },
3127*4882a593Smuzhiyun };
3128*4882a593Smuzhiyun 
3129*4882a593Smuzhiyun static const struct regmap_access_table it6616_hdmi_volatile_table = {
3130*4882a593Smuzhiyun 	.yes_ranges = it6616_hdmi_volatile_ranges,
3131*4882a593Smuzhiyun 	.n_yes_ranges = ARRAY_SIZE(it6616_hdmi_volatile_ranges),
3132*4882a593Smuzhiyun };
3133*4882a593Smuzhiyun 
3134*4882a593Smuzhiyun static const struct regmap_config it6616_hdmi_regmap_config = {
3135*4882a593Smuzhiyun 	.reg_bits = 8,
3136*4882a593Smuzhiyun 	.val_bits = 8,
3137*4882a593Smuzhiyun 	.volatile_table = &it6616_hdmi_volatile_table,
3138*4882a593Smuzhiyun 	.cache_type = REGCACHE_NONE,
3139*4882a593Smuzhiyun };
3140*4882a593Smuzhiyun 
3141*4882a593Smuzhiyun static const struct regmap_range it6616_mipi_volatile_ranges[] = {
3142*4882a593Smuzhiyun 	{ .range_min = 0, .range_max = 0xff },
3143*4882a593Smuzhiyun };
3144*4882a593Smuzhiyun 
3145*4882a593Smuzhiyun static const struct regmap_access_table it6616_mipi_volatile_table = {
3146*4882a593Smuzhiyun 	.yes_ranges = it6616_mipi_volatile_ranges,
3147*4882a593Smuzhiyun 	.n_yes_ranges = ARRAY_SIZE(it6616_mipi_volatile_ranges),
3148*4882a593Smuzhiyun };
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun static const struct regmap_config it6616_mipi_regmap_config = {
3151*4882a593Smuzhiyun 	.reg_bits = 8,
3152*4882a593Smuzhiyun 	.val_bits = 8,
3153*4882a593Smuzhiyun 	.volatile_table = &it6616_mipi_volatile_table,
3154*4882a593Smuzhiyun 	.cache_type = REGCACHE_NONE,
3155*4882a593Smuzhiyun };
3156*4882a593Smuzhiyun 
3157*4882a593Smuzhiyun static const struct regmap_range it6616_edid_volatile_ranges[] = {
3158*4882a593Smuzhiyun 	{ .range_min = 0, .range_max = 0xff },
3159*4882a593Smuzhiyun };
3160*4882a593Smuzhiyun 
3161*4882a593Smuzhiyun static const struct regmap_access_table it6616_edid_volatile_table = {
3162*4882a593Smuzhiyun 	.yes_ranges = it6616_edid_volatile_ranges,
3163*4882a593Smuzhiyun 	.n_yes_ranges = ARRAY_SIZE(it6616_edid_volatile_ranges),
3164*4882a593Smuzhiyun };
3165*4882a593Smuzhiyun 
3166*4882a593Smuzhiyun static const struct regmap_config it6616_edid_regmap_config = {
3167*4882a593Smuzhiyun 	.reg_bits = 8,
3168*4882a593Smuzhiyun 	.val_bits = 8,
3169*4882a593Smuzhiyun 	.volatile_table = &it6616_edid_volatile_table,
3170*4882a593Smuzhiyun 	.cache_type = REGCACHE_NONE,
3171*4882a593Smuzhiyun };
3172*4882a593Smuzhiyun 
attr_buffer_put(char * buf,char * reg_buf)3173*4882a593Smuzhiyun static ssize_t attr_buffer_put(char *buf, char *reg_buf)
3174*4882a593Smuzhiyun {
3175*4882a593Smuzhiyun 	int i = 0;
3176*4882a593Smuzhiyun 	char *str = buf, *end = buf + PAGE_SIZE;
3177*4882a593Smuzhiyun 
3178*4882a593Smuzhiyun 	str += scnprintf(str, end - str,
3179*4882a593Smuzhiyun 	"     0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07");
3180*4882a593Smuzhiyun 	str += scnprintf(str, end - str,
3181*4882a593Smuzhiyun 	" 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F\n");
3182*4882a593Smuzhiyun 	str += scnprintf(str, end - str,
3183*4882a593Smuzhiyun 	"=============================================");
3184*4882a593Smuzhiyun 	str += scnprintf(str, end - str,
3185*4882a593Smuzhiyun 	"=======================================");
3186*4882a593Smuzhiyun 
3187*4882a593Smuzhiyun 	for (i = 0; i < 256; i++) {
3188*4882a593Smuzhiyun 		if (i % 16 == 0)
3189*4882a593Smuzhiyun 			str += scnprintf(str, end - str, "\n[%02X] ", i & 0xF0);
3190*4882a593Smuzhiyun 		str += scnprintf(str, end - str, "0x%02X ", reg_buf[i]);
3191*4882a593Smuzhiyun 	}
3192*4882a593Smuzhiyun 	str += scnprintf(str, end - str, "\n");
3193*4882a593Smuzhiyun 
3194*4882a593Smuzhiyun 	return end - str;
3195*4882a593Smuzhiyun }
edid_ram_show(struct device * dev,struct device_attribute * attr,char * buf)3196*4882a593Smuzhiyun static ssize_t edid_ram_show(struct device *dev,
3197*4882a593Smuzhiyun 			struct device_attribute *attr, char *buf)
3198*4882a593Smuzhiyun {
3199*4882a593Smuzhiyun 	struct it6616 *it6616 = dev_get_drvdata(dev);
3200*4882a593Smuzhiyun 
3201*4882a593Smuzhiyun 	u8 reg_buf[256];
3202*4882a593Smuzhiyun 
3203*4882a593Smuzhiyun 	dev_info(dev, "%s(%x)\n", __func__, it6616->attr_hdmi_reg_bank);
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3206*4882a593Smuzhiyun 	it6616_hdmi_edid_ram_get(it6616, reg_buf);
3207*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3208*4882a593Smuzhiyun 
3209*4882a593Smuzhiyun 	return attr_buffer_put(buf, reg_buf);
3210*4882a593Smuzhiyun }
3211*4882a593Smuzhiyun 
hdmi_reg_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3212*4882a593Smuzhiyun static ssize_t hdmi_reg_store(struct device *dev,
3213*4882a593Smuzhiyun 			struct device_attribute *attr, const char *buf, size_t count)
3214*4882a593Smuzhiyun {
3215*4882a593Smuzhiyun 	struct it6616 *it6616 = dev_get_drvdata(dev);
3216*4882a593Smuzhiyun 	int reg_bank;
3217*4882a593Smuzhiyun 
3218*4882a593Smuzhiyun 	if (kstrtoint(buf, 10, &reg_bank) < 0)
3219*4882a593Smuzhiyun 		return -EINVAL;
3220*4882a593Smuzhiyun 
3221*4882a593Smuzhiyun 	it6616->attr_hdmi_reg_bank = (u8) reg_bank;
3222*4882a593Smuzhiyun 
3223*4882a593Smuzhiyun 	dev_info(dev, "%s() %d, %x\n",
3224*4882a593Smuzhiyun 		__func__, reg_bank, it6616->attr_hdmi_reg_bank);
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	return count;
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun 
hdmi_reg_show(struct device * dev,struct device_attribute * attr,char * buf)3230*4882a593Smuzhiyun static ssize_t hdmi_reg_show(struct device *dev,
3231*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
3232*4882a593Smuzhiyun {
3233*4882a593Smuzhiyun 	struct it6616 *it6616 = dev_get_drvdata(dev);
3234*4882a593Smuzhiyun 	struct regmap *hdmi = it6616->hdmi_regmap;
3235*4882a593Smuzhiyun 	int i;
3236*4882a593Smuzhiyun 	u8 reg_buf[256];
3237*4882a593Smuzhiyun 
3238*4882a593Smuzhiyun 	dev_info(dev, "%s(%x)\n", __func__, it6616->attr_hdmi_reg_bank);
3239*4882a593Smuzhiyun 
3240*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3241*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, it6616->attr_hdmi_reg_bank);
3242*4882a593Smuzhiyun 	for (i = 0; i < 256; i++)
3243*4882a593Smuzhiyun 		reg_buf[i] = it6616_hdmi_read(hdmi, i);
3244*4882a593Smuzhiyun 	//regmap_bulk_read(dp, 0, reg_buf, 256);
3245*4882a593Smuzhiyun 	it6616_hdmi_chgbank(hdmi, 0);
3246*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3247*4882a593Smuzhiyun 
3248*4882a593Smuzhiyun 	return  attr_buffer_put(buf, reg_buf);
3249*4882a593Smuzhiyun }
3250*4882a593Smuzhiyun 
mipi_reg_show(struct device * dev,struct device_attribute * attr,char * buf)3251*4882a593Smuzhiyun static ssize_t mipi_reg_show(struct device *dev,
3252*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
3253*4882a593Smuzhiyun {
3254*4882a593Smuzhiyun 	struct it6616 *it6616 = dev_get_drvdata(dev);
3255*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
3256*4882a593Smuzhiyun 	int i;
3257*4882a593Smuzhiyun 	u8 reg_buf[256];
3258*4882a593Smuzhiyun 
3259*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3260*4882a593Smuzhiyun 	for (i = 0; i < 256; i++)
3261*4882a593Smuzhiyun 		reg_buf[i] = it6616_mipi_tx_read(mipi, i);
3262*4882a593Smuzhiyun 	//regmap_bulk_read(mipi, 0, reg_buf, 256);
3263*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3264*4882a593Smuzhiyun 
3265*4882a593Smuzhiyun 	return  attr_buffer_put(buf, reg_buf);
3266*4882a593Smuzhiyun }
3267*4882a593Smuzhiyun 
mipi_reg_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)3268*4882a593Smuzhiyun static ssize_t mipi_reg_store(struct device *dev,
3269*4882a593Smuzhiyun 	struct device_attribute *attr, const char *buf, size_t size)
3270*4882a593Smuzhiyun {
3271*4882a593Smuzhiyun 	struct it6616 *it6616 = dev_get_drvdata(dev);
3272*4882a593Smuzhiyun 	struct regmap *mipi = it6616->mipi_regmap;
3273*4882a593Smuzhiyun 	unsigned int addr, val;
3274*4882a593Smuzhiyun 	int ret;
3275*4882a593Smuzhiyun 
3276*4882a593Smuzhiyun 	ret = sscanf(buf, "%X %X ", &addr, &val);
3277*4882a593Smuzhiyun 	if (ret) {
3278*4882a593Smuzhiyun 		dev_info(dev, "addr= %2.2X\n", addr);
3279*4882a593Smuzhiyun 		dev_info(dev, "val = %2.2X\n", val);
3280*4882a593Smuzhiyun 		if (((addr <= 0xFF) && (addr >= 0x00)) && ((val <= 0xFF) && (val >= 0x00)))
3281*4882a593Smuzhiyun 			regmap_write(mipi, addr, val);
3282*4882a593Smuzhiyun 	} else {
3283*4882a593Smuzhiyun 		dev_info(dev, "it6616_fwrite_mipi_reg , error[%s]\n", buf);
3284*4882a593Smuzhiyun 	}
3285*4882a593Smuzhiyun 
3286*4882a593Smuzhiyun 	return size;
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun static DEVICE_ATTR_RW(mipi_reg);
3290*4882a593Smuzhiyun static DEVICE_ATTR_RO(edid_ram);
3291*4882a593Smuzhiyun static DEVICE_ATTR_RW(hdmi_reg);
3292*4882a593Smuzhiyun 
3293*4882a593Smuzhiyun static const struct attribute *it6616_attrs[] = {
3294*4882a593Smuzhiyun 	&dev_attr_hdmi_reg.attr,
3295*4882a593Smuzhiyun 	&dev_attr_mipi_reg.attr,
3296*4882a593Smuzhiyun 	&dev_attr_edid_ram.attr,
3297*4882a593Smuzhiyun 	NULL,
3298*4882a593Smuzhiyun };
3299*4882a593Smuzhiyun 
tx_5v_power_present(struct v4l2_subdev * sd)3300*4882a593Smuzhiyun static inline bool tx_5v_power_present(struct v4l2_subdev *sd)
3301*4882a593Smuzhiyun {
3302*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3303*4882a593Smuzhiyun 
3304*4882a593Smuzhiyun 	return it6616_hdmi_is_5v_on(it6616);
3305*4882a593Smuzhiyun }
3306*4882a593Smuzhiyun 
no_signal(struct v4l2_subdev * sd)3307*4882a593Smuzhiyun static inline bool no_signal(struct v4l2_subdev *sd)
3308*4882a593Smuzhiyun {
3309*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s no signal:%d\n", __func__,
3312*4882a593Smuzhiyun 			it6616->nosignal);
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun 	return it6616->nosignal;
3315*4882a593Smuzhiyun }
3316*4882a593Smuzhiyun 
audio_present(struct v4l2_subdev * sd)3317*4882a593Smuzhiyun static inline bool audio_present(struct v4l2_subdev *sd)
3318*4882a593Smuzhiyun {
3319*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun 	return it6616->is_audio_present;
3322*4882a593Smuzhiyun }
3323*4882a593Smuzhiyun 
get_audio_sampling_rate(struct v4l2_subdev * sd)3324*4882a593Smuzhiyun static int get_audio_sampling_rate(struct v4l2_subdev *sd)
3325*4882a593Smuzhiyun {
3326*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3327*4882a593Smuzhiyun 
3328*4882a593Smuzhiyun 	if (no_signal(sd))
3329*4882a593Smuzhiyun 		return 0;
3330*4882a593Smuzhiyun 
3331*4882a593Smuzhiyun 	return code_to_rate_table[it6616->ainfo.force_sample_freq];
3332*4882a593Smuzhiyun }
3333*4882a593Smuzhiyun 
fps_calc(const struct v4l2_bt_timings * t)3334*4882a593Smuzhiyun static inline unsigned int fps_calc(const struct v4l2_bt_timings *t)
3335*4882a593Smuzhiyun {
3336*4882a593Smuzhiyun 	if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t))
3337*4882a593Smuzhiyun 		return 0;
3338*4882a593Smuzhiyun 
3339*4882a593Smuzhiyun 	return DIV_ROUND_CLOSEST((unsigned int)t->pixelclock,
3340*4882a593Smuzhiyun 			V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t));
3341*4882a593Smuzhiyun }
3342*4882a593Smuzhiyun 
it6616_rcv_supported_res(struct v4l2_subdev * sd,u32 width,u32 height)3343*4882a593Smuzhiyun static bool it6616_rcv_supported_res(struct v4l2_subdev *sd, u32 width,
3344*4882a593Smuzhiyun 				u32 height)
3345*4882a593Smuzhiyun {
3346*4882a593Smuzhiyun 	u32 i;
3347*4882a593Smuzhiyun 
3348*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
3349*4882a593Smuzhiyun 		if ((supported_modes[i].width == width) &&
3350*4882a593Smuzhiyun 		    (supported_modes[i].height == height)) {
3351*4882a593Smuzhiyun 			break;
3352*4882a593Smuzhiyun 		}
3353*4882a593Smuzhiyun 	}
3354*4882a593Smuzhiyun 
3355*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(supported_modes)) {
3356*4882a593Smuzhiyun 		v4l2_err(sd, "%s do not support res wxh: %dx%d\n", __func__,
3357*4882a593Smuzhiyun 				width, height);
3358*4882a593Smuzhiyun 		return false;
3359*4882a593Smuzhiyun 	} else {
3360*4882a593Smuzhiyun 		return true;
3361*4882a593Smuzhiyun 	}
3362*4882a593Smuzhiyun }
3363*4882a593Smuzhiyun 
it6616_get_detected_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)3364*4882a593Smuzhiyun static int it6616_get_detected_timings(struct v4l2_subdev *sd,
3365*4882a593Smuzhiyun 				     struct v4l2_dv_timings *timings)
3366*4882a593Smuzhiyun {
3367*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3368*4882a593Smuzhiyun 	struct v4l2_bt_timings *bt = &timings->bt;
3369*4882a593Smuzhiyun 	u32 fps, htotal, vtotal;
3370*4882a593Smuzhiyun 
3371*4882a593Smuzhiyun 	memset(timings, 0, sizeof(struct v4l2_dv_timings));
3372*4882a593Smuzhiyun 	it6616_hdmi_rx_get_video_info(it6616);
3373*4882a593Smuzhiyun 
3374*4882a593Smuzhiyun 	it6616->nosignal = false;
3375*4882a593Smuzhiyun 	it6616->is_audio_present = tx_5v_power_present(sd) ? true : false;
3376*4882a593Smuzhiyun 	timings->type = V4L2_DV_BT_656_1120;
3377*4882a593Smuzhiyun 	bt->interlaced = it6616->vinfo.interlaced;
3378*4882a593Smuzhiyun 	bt->width = it6616->vinfo.h_active;
3379*4882a593Smuzhiyun 	bt->height = it6616->vinfo.v_active;
3380*4882a593Smuzhiyun 	bt->vsync = it6616->vinfo.v_sync_w;
3381*4882a593Smuzhiyun 	bt->hsync = it6616->vinfo.h_sync_w;
3382*4882a593Smuzhiyun 	bt->pixelclock = it6616->vinfo.pclk * 1000;
3383*4882a593Smuzhiyun 	bt->hfrontporch = it6616->vinfo.h_front_porch;
3384*4882a593Smuzhiyun 	bt->vfrontporch = it6616->vinfo.v_front_porch;
3385*4882a593Smuzhiyun 	bt->hbackporch = it6616->vinfo.h_back_porch;
3386*4882a593Smuzhiyun 	bt->vbackporch = it6616->vinfo.v_back_porch;
3387*4882a593Smuzhiyun 	htotal = it6616->vinfo.h_total;
3388*4882a593Smuzhiyun 	vtotal = it6616->vinfo.v_total;
3389*4882a593Smuzhiyun 
3390*4882a593Smuzhiyun 	if (it6616->avi_if.colorspace == HDMI_COLORSPACE_YUV420) {
3391*4882a593Smuzhiyun 		bt->width = it6616->vinfo.h_active * 2;
3392*4882a593Smuzhiyun 		bt->hfrontporch = it6616->vinfo.h_front_porch * 2;
3393*4882a593Smuzhiyun 		bt->hbackporch = it6616->vinfo.h_back_porch * 2;
3394*4882a593Smuzhiyun 		bt->hsync = it6616->vinfo.h_sync_w * 2;
3395*4882a593Smuzhiyun 		htotal = it6616->vinfo.h_total * 2;
3396*4882a593Smuzhiyun 	}
3397*4882a593Smuzhiyun 
3398*4882a593Smuzhiyun 	fps = fps_calc(bt);
3399*4882a593Smuzhiyun 
3400*4882a593Smuzhiyun 	if (!it6616_rcv_supported_res(sd, bt->width, bt->height)) {
3401*4882a593Smuzhiyun 		it6616->nosignal = true;
3402*4882a593Smuzhiyun 		v4l2_err(sd, "%s: rcv err res, return no signal!\n", __func__);
3403*4882a593Smuzhiyun 		return -EINVAL;
3404*4882a593Smuzhiyun 	}
3405*4882a593Smuzhiyun 
3406*4882a593Smuzhiyun 	/* for interlaced res*/
3407*4882a593Smuzhiyun 	if (bt->interlaced) {
3408*4882a593Smuzhiyun 		bt->height *= 2;
3409*4882a593Smuzhiyun 		bt->il_vsync = bt->vsync + 1;
3410*4882a593Smuzhiyun 	}
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "act:%dx%d, total:%dx%d, pixclk:%d, fps:%d\n",
3413*4882a593Smuzhiyun 			bt->width, bt->height, htotal, vtotal, bt->pixelclock, fps);
3414*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d\n",
3415*4882a593Smuzhiyun 			bt->hfrontporch, bt->hsync, bt->hbackporch,
3416*4882a593Smuzhiyun 			bt->vfrontporch, bt->vsync, bt->vbackporch);
3417*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "inerlaced:%d,\n", bt->interlaced);
3418*4882a593Smuzhiyun 
3419*4882a593Smuzhiyun 	return 0;
3420*4882a593Smuzhiyun }
3421*4882a593Smuzhiyun 
it6616_s_ctrl_detect_tx_5v(struct v4l2_subdev * sd)3422*4882a593Smuzhiyun static int it6616_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd)
3423*4882a593Smuzhiyun {
3424*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3425*4882a593Smuzhiyun 
3426*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(it6616->detect_tx_5v_ctrl,
3427*4882a593Smuzhiyun 			tx_5v_power_present(sd));
3428*4882a593Smuzhiyun }
3429*4882a593Smuzhiyun 
it6616_s_ctrl_audio_sampling_rate(struct v4l2_subdev * sd)3430*4882a593Smuzhiyun static int it6616_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd)
3431*4882a593Smuzhiyun {
3432*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3433*4882a593Smuzhiyun 
3434*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(it6616->audio_sampling_rate_ctrl,
3435*4882a593Smuzhiyun 			get_audio_sampling_rate(sd));
3436*4882a593Smuzhiyun }
3437*4882a593Smuzhiyun 
it6616_s_ctrl_audio_present(struct v4l2_subdev * sd)3438*4882a593Smuzhiyun static int it6616_s_ctrl_audio_present(struct v4l2_subdev *sd)
3439*4882a593Smuzhiyun {
3440*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3441*4882a593Smuzhiyun 
3442*4882a593Smuzhiyun 	return v4l2_ctrl_s_ctrl(it6616->audio_present_ctrl,
3443*4882a593Smuzhiyun 			audio_present(sd));
3444*4882a593Smuzhiyun }
3445*4882a593Smuzhiyun 
it6616_update_controls(struct v4l2_subdev * sd)3446*4882a593Smuzhiyun static int it6616_update_controls(struct v4l2_subdev *sd)
3447*4882a593Smuzhiyun {
3448*4882a593Smuzhiyun 	int ret = 0;
3449*4882a593Smuzhiyun 
3450*4882a593Smuzhiyun 	ret |= it6616_s_ctrl_detect_tx_5v(sd);
3451*4882a593Smuzhiyun 	ret |= it6616_s_ctrl_audio_sampling_rate(sd);
3452*4882a593Smuzhiyun 	ret |= it6616_s_ctrl_audio_present(sd);
3453*4882a593Smuzhiyun 
3454*4882a593Smuzhiyun 	return ret;
3455*4882a593Smuzhiyun }
3456*4882a593Smuzhiyun 
it6616_match_dv_timings(const struct v4l2_dv_timings * t1,const struct v4l2_dv_timings * t2)3457*4882a593Smuzhiyun static bool it6616_match_dv_timings(const struct v4l2_dv_timings *t1,
3458*4882a593Smuzhiyun 				const struct v4l2_dv_timings *t2)
3459*4882a593Smuzhiyun {
3460*4882a593Smuzhiyun 	if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120)
3461*4882a593Smuzhiyun 		return false;
3462*4882a593Smuzhiyun 	if (t1->bt.width == t2->bt.width &&
3463*4882a593Smuzhiyun 		t1->bt.height == t2->bt.height &&
3464*4882a593Smuzhiyun 		t1->bt.interlaced == t2->bt.interlaced &&
3465*4882a593Smuzhiyun 		t1->bt.hfrontporch == t2->bt.hfrontporch &&
3466*4882a593Smuzhiyun 		t1->bt.hsync == t2->bt.hsync &&
3467*4882a593Smuzhiyun 		t1->bt.hbackporch == t2->bt.hbackporch &&
3468*4882a593Smuzhiyun 		t1->bt.vfrontporch == t2->bt.vfrontporch &&
3469*4882a593Smuzhiyun 		t1->bt.vsync == t2->bt.vsync &&
3470*4882a593Smuzhiyun 		t1->bt.vbackporch == t2->bt.vbackporch &&
3471*4882a593Smuzhiyun 		(!t1->bt.interlaced ||
3472*4882a593Smuzhiyun 		(t1->bt.il_vfrontporch == t2->bt.il_vfrontporch &&
3473*4882a593Smuzhiyun 		t1->bt.il_vsync == t2->bt.il_vsync &&
3474*4882a593Smuzhiyun 		t1->bt.il_vbackporch == t2->bt.il_vbackporch)))
3475*4882a593Smuzhiyun 		return true;
3476*4882a593Smuzhiyun 	return false;
3477*4882a593Smuzhiyun }
3478*4882a593Smuzhiyun 
it6616_format_change(struct v4l2_subdev * sd)3479*4882a593Smuzhiyun static void it6616_format_change(struct v4l2_subdev *sd)
3480*4882a593Smuzhiyun {
3481*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3482*4882a593Smuzhiyun 	struct v4l2_dv_timings timings;
3483*4882a593Smuzhiyun 	const struct v4l2_event it6616_ev_fmt = {
3484*4882a593Smuzhiyun 		.type = V4L2_EVENT_SOURCE_CHANGE,
3485*4882a593Smuzhiyun 		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
3486*4882a593Smuzhiyun 	};
3487*4882a593Smuzhiyun 
3488*4882a593Smuzhiyun 	it6616_get_detected_timings(sd, &timings);
3489*4882a593Smuzhiyun 
3490*4882a593Smuzhiyun 	if (!it6616_match_dv_timings(&it6616->timings, &timings)) {
3491*4882a593Smuzhiyun 		/* automatically set timing rather than set by user */
3492*4882a593Smuzhiyun 		it6616_s_dv_timings(sd, &timings);
3493*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name,
3494*4882a593Smuzhiyun 				"Format_change: New format: ",
3495*4882a593Smuzhiyun 				&timings, false);
3496*4882a593Smuzhiyun 		if (sd->devnode)
3497*4882a593Smuzhiyun 			v4l2_subdev_notify_event(sd, &it6616_ev_fmt);
3498*4882a593Smuzhiyun 	}
3499*4882a593Smuzhiyun }
3500*4882a593Smuzhiyun 
it6616_isr(struct v4l2_subdev * sd,u32 status,bool * handled)3501*4882a593Smuzhiyun static int it6616_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
3502*4882a593Smuzhiyun {
3503*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3504*4882a593Smuzhiyun 	static struct v4l2_dv_timings default_timing =
3505*4882a593Smuzhiyun 		V4L2_DV_BT_CEA_640X480P59_94;
3506*4882a593Smuzhiyun 
3507*4882a593Smuzhiyun 	if (tx_5v_power_present(sd)) {
3508*4882a593Smuzhiyun 		it6616_poll_threaded_handler(it6616);
3509*4882a593Smuzhiyun 		it6616_intp_threaded_handler(0, it6616);
3510*4882a593Smuzhiyun 		it6616_format_change(sd);
3511*4882a593Smuzhiyun 	} else {
3512*4882a593Smuzhiyun 		it6616_s_dv_timings(sd, &default_timing);
3513*4882a593Smuzhiyun 		it6616->nosignal = true;
3514*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: HDMI unplug!!!\n", __func__);
3515*4882a593Smuzhiyun 	}
3516*4882a593Smuzhiyun 
3517*4882a593Smuzhiyun 	*handled = true;
3518*4882a593Smuzhiyun 
3519*4882a593Smuzhiyun 	return 0;
3520*4882a593Smuzhiyun }
3521*4882a593Smuzhiyun 
it6616_detect_hot_plug(struct v4l2_subdev * sd)3522*4882a593Smuzhiyun static void it6616_detect_hot_plug(struct v4l2_subdev *sd)
3523*4882a593Smuzhiyun {
3524*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3525*4882a593Smuzhiyun 
3526*4882a593Smuzhiyun 	if (it6616->mipi_tx_video_stable && it6616_hdmi_is_5v_on(it6616))
3527*4882a593Smuzhiyun 		v4l2_ctrl_s_ctrl(it6616->detect_tx_5v_ctrl, 1);
3528*4882a593Smuzhiyun 	else
3529*4882a593Smuzhiyun 		v4l2_ctrl_s_ctrl(it6616->detect_tx_5v_ctrl, 0);
3530*4882a593Smuzhiyun }
3531*4882a593Smuzhiyun 
it6616_work_i2c_poll(struct work_struct * work)3532*4882a593Smuzhiyun static void it6616_work_i2c_poll(struct work_struct *work)
3533*4882a593Smuzhiyun {
3534*4882a593Smuzhiyun 	struct delayed_work *dwork = to_delayed_work(work);
3535*4882a593Smuzhiyun 	struct it6616 *it6616 = container_of(dwork,
3536*4882a593Smuzhiyun 			struct it6616, work_i2c_poll);
3537*4882a593Smuzhiyun 	bool handled;
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun 	it6616_isr(&it6616->sd, 0, &handled);
3540*4882a593Smuzhiyun 	it6616_detect_hot_plug(&it6616->sd);
3541*4882a593Smuzhiyun 	schedule_delayed_work(&it6616->work_i2c_poll,
3542*4882a593Smuzhiyun 			msecs_to_jiffies(POLL_INTERVAL_MS));
3543*4882a593Smuzhiyun }
3544*4882a593Smuzhiyun 
it6616_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)3545*4882a593Smuzhiyun static int it6616_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
3546*4882a593Smuzhiyun 				    struct v4l2_event_subscription *sub)
3547*4882a593Smuzhiyun {
3548*4882a593Smuzhiyun 	switch (sub->type) {
3549*4882a593Smuzhiyun 	case V4L2_EVENT_SOURCE_CHANGE:
3550*4882a593Smuzhiyun 		return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
3551*4882a593Smuzhiyun 	case V4L2_EVENT_CTRL:
3552*4882a593Smuzhiyun 		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
3553*4882a593Smuzhiyun 	default:
3554*4882a593Smuzhiyun 		return -EINVAL;
3555*4882a593Smuzhiyun 	}
3556*4882a593Smuzhiyun }
3557*4882a593Smuzhiyun 
it6616_g_input_status(struct v4l2_subdev * sd,u32 * status)3558*4882a593Smuzhiyun static int it6616_g_input_status(struct v4l2_subdev *sd, u32 *status)
3559*4882a593Smuzhiyun {
3560*4882a593Smuzhiyun 	*status = 0;
3561*4882a593Smuzhiyun 	*status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
3562*4882a593Smuzhiyun 
3563*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
3564*4882a593Smuzhiyun 
3565*4882a593Smuzhiyun 	return 0;
3566*4882a593Smuzhiyun }
3567*4882a593Smuzhiyun 
it6616_s_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)3568*4882a593Smuzhiyun static int it6616_s_dv_timings(struct v4l2_subdev *sd,
3569*4882a593Smuzhiyun 				 struct v4l2_dv_timings *timings)
3570*4882a593Smuzhiyun {
3571*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3572*4882a593Smuzhiyun 
3573*4882a593Smuzhiyun 	if (!timings)
3574*4882a593Smuzhiyun 		return -EINVAL;
3575*4882a593Smuzhiyun 
3576*4882a593Smuzhiyun 	if (debug)
3577*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name, "s_dv_timings: ",
3578*4882a593Smuzhiyun 				timings, false);
3579*4882a593Smuzhiyun 
3580*4882a593Smuzhiyun 	if (v4l2_match_dv_timings(&it6616->timings, timings, 0, false)) {
3581*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
3582*4882a593Smuzhiyun 		return 0;
3583*4882a593Smuzhiyun 	}
3584*4882a593Smuzhiyun 
3585*4882a593Smuzhiyun 	if (!v4l2_valid_dv_timings(timings,
3586*4882a593Smuzhiyun 				&it6616_timings_cap, NULL, NULL)) {
3587*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
3588*4882a593Smuzhiyun 		return -ERANGE;
3589*4882a593Smuzhiyun 	}
3590*4882a593Smuzhiyun 
3591*4882a593Smuzhiyun 	it6616->timings = *timings;
3592*4882a593Smuzhiyun 
3593*4882a593Smuzhiyun 	return 0;
3594*4882a593Smuzhiyun }
3595*4882a593Smuzhiyun 
it6616_g_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)3596*4882a593Smuzhiyun static int it6616_g_dv_timings(struct v4l2_subdev *sd,
3597*4882a593Smuzhiyun 				struct v4l2_dv_timings *timings)
3598*4882a593Smuzhiyun {
3599*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3600*4882a593Smuzhiyun 
3601*4882a593Smuzhiyun 	*timings = it6616->timings;
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun 	return 0;
3604*4882a593Smuzhiyun }
3605*4882a593Smuzhiyun 
it6616_enum_dv_timings(struct v4l2_subdev * sd,struct v4l2_enum_dv_timings * timings)3606*4882a593Smuzhiyun static int it6616_enum_dv_timings(struct v4l2_subdev *sd,
3607*4882a593Smuzhiyun 				struct v4l2_enum_dv_timings *timings)
3608*4882a593Smuzhiyun {
3609*4882a593Smuzhiyun 	if (timings->pad != 0)
3610*4882a593Smuzhiyun 		return -EINVAL;
3611*4882a593Smuzhiyun 
3612*4882a593Smuzhiyun 	return v4l2_enum_dv_timings_cap(timings,
3613*4882a593Smuzhiyun 			&it6616_timings_cap, NULL, NULL);
3614*4882a593Smuzhiyun }
3615*4882a593Smuzhiyun 
it6616_query_dv_timings(struct v4l2_subdev * sd,struct v4l2_dv_timings * timings)3616*4882a593Smuzhiyun static int it6616_query_dv_timings(struct v4l2_subdev *sd,
3617*4882a593Smuzhiyun 				struct v4l2_dv_timings *timings)
3618*4882a593Smuzhiyun {
3619*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3620*4882a593Smuzhiyun 
3621*4882a593Smuzhiyun 	*timings = it6616->timings;
3622*4882a593Smuzhiyun 	if (debug)
3623*4882a593Smuzhiyun 		v4l2_print_dv_timings(sd->name,
3624*4882a593Smuzhiyun 				"query_dv_timings: ", timings, false);
3625*4882a593Smuzhiyun 
3626*4882a593Smuzhiyun 	if (!v4l2_valid_dv_timings(timings, &it6616_timings_cap, NULL,
3627*4882a593Smuzhiyun 				NULL)) {
3628*4882a593Smuzhiyun 		v4l2_dbg(1, debug, sd, "%s: timings out of range\n",
3629*4882a593Smuzhiyun 				__func__);
3630*4882a593Smuzhiyun 
3631*4882a593Smuzhiyun 		return -ERANGE;
3632*4882a593Smuzhiyun 	}
3633*4882a593Smuzhiyun 
3634*4882a593Smuzhiyun 	return 0;
3635*4882a593Smuzhiyun }
3636*4882a593Smuzhiyun 
it6616_dv_timings_cap(struct v4l2_subdev * sd,struct v4l2_dv_timings_cap * cap)3637*4882a593Smuzhiyun static int it6616_dv_timings_cap(struct v4l2_subdev *sd,
3638*4882a593Smuzhiyun 				struct v4l2_dv_timings_cap *cap)
3639*4882a593Smuzhiyun {
3640*4882a593Smuzhiyun 	if (cap->pad != 0)
3641*4882a593Smuzhiyun 		return -EINVAL;
3642*4882a593Smuzhiyun 
3643*4882a593Smuzhiyun 	*cap = it6616_timings_cap;
3644*4882a593Smuzhiyun 
3645*4882a593Smuzhiyun 	return 0;
3646*4882a593Smuzhiyun }
3647*4882a593Smuzhiyun 
it6616_g_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)3648*4882a593Smuzhiyun static int it6616_g_mbus_config(struct v4l2_subdev *sd,
3649*4882a593Smuzhiyun 			unsigned int pad, struct v4l2_mbus_config *cfg)
3650*4882a593Smuzhiyun {
3651*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun 	cfg->type = V4L2_MBUS_CSI2_DPHY;
3654*4882a593Smuzhiyun 	cfg->flags = V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
3655*4882a593Smuzhiyun 			V4L2_MBUS_CSI2_CHANNEL_0;
3656*4882a593Smuzhiyun 
3657*4882a593Smuzhiyun 	switch (it6616->csi_lanes_in_use) {
3658*4882a593Smuzhiyun 	case 1:
3659*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
3660*4882a593Smuzhiyun 		break;
3661*4882a593Smuzhiyun 	case 2:
3662*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
3663*4882a593Smuzhiyun 		break;
3664*4882a593Smuzhiyun 	case 3:
3665*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_3_LANE;
3666*4882a593Smuzhiyun 		break;
3667*4882a593Smuzhiyun 	case 4:
3668*4882a593Smuzhiyun 		cfg->flags |= V4L2_MBUS_CSI2_4_LANE;
3669*4882a593Smuzhiyun 		break;
3670*4882a593Smuzhiyun 
3671*4882a593Smuzhiyun 	default:
3672*4882a593Smuzhiyun 		return -EINVAL;
3673*4882a593Smuzhiyun 	}
3674*4882a593Smuzhiyun 
3675*4882a593Smuzhiyun 	return 0;
3676*4882a593Smuzhiyun }
3677*4882a593Smuzhiyun 
__it6616_start_stream(struct it6616 * it6616)3678*4882a593Smuzhiyun static int __it6616_start_stream(struct it6616 *it6616)
3679*4882a593Smuzhiyun {
3680*4882a593Smuzhiyun 	it6616_mipitx_output_disable(it6616);
3681*4882a593Smuzhiyun 	usleep_range(1000, 2000);
3682*4882a593Smuzhiyun 	it6616_mipi_tx_output_enable(it6616);
3683*4882a593Smuzhiyun 
3684*4882a593Smuzhiyun 	return 0;
3685*4882a593Smuzhiyun }
3686*4882a593Smuzhiyun 
__it6616_stop_stream(struct it6616 * it6616)3687*4882a593Smuzhiyun static int __it6616_stop_stream(struct it6616 *it6616)
3688*4882a593Smuzhiyun {
3689*4882a593Smuzhiyun 	it6616_mipitx_output_disable(it6616);
3690*4882a593Smuzhiyun 
3691*4882a593Smuzhiyun 	return 0;
3692*4882a593Smuzhiyun }
3693*4882a593Smuzhiyun 
it6616_s_stream(struct v4l2_subdev * sd,int on)3694*4882a593Smuzhiyun static int it6616_s_stream(struct v4l2_subdev *sd, int on)
3695*4882a593Smuzhiyun {
3696*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3697*4882a593Smuzhiyun 	struct i2c_client *client = it6616->i2c_client;
3698*4882a593Smuzhiyun 	int ret = 0;
3699*4882a593Smuzhiyun 
3700*4882a593Smuzhiyun 	dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,
3701*4882a593Smuzhiyun 				it6616->cur_mode->width,
3702*4882a593Smuzhiyun 				it6616->cur_mode->height,
3703*4882a593Smuzhiyun 		DIV_ROUND_CLOSEST(it6616->cur_mode->max_fps.denominator,
3704*4882a593Smuzhiyun 				  it6616->cur_mode->max_fps.numerator));
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3707*4882a593Smuzhiyun 	on = !!on;
3708*4882a593Smuzhiyun 
3709*4882a593Smuzhiyun 	if (on) {
3710*4882a593Smuzhiyun 		ret = __it6616_start_stream(it6616);
3711*4882a593Smuzhiyun 		if (ret) {
3712*4882a593Smuzhiyun 			dev_err(it6616->dev, "Failed to start it6616 stream\n");
3713*4882a593Smuzhiyun 			goto unlock_and_return;
3714*4882a593Smuzhiyun 		}
3715*4882a593Smuzhiyun 	} else {
3716*4882a593Smuzhiyun 		__it6616_stop_stream(it6616);
3717*4882a593Smuzhiyun 	}
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun 
3720*4882a593Smuzhiyun unlock_and_return:
3721*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3722*4882a593Smuzhiyun 	return 0;
3723*4882a593Smuzhiyun }
3724*4882a593Smuzhiyun 
it6616_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)3725*4882a593Smuzhiyun static int it6616_enum_mbus_code(struct v4l2_subdev *sd,
3726*4882a593Smuzhiyun 			struct v4l2_subdev_pad_config *cfg,
3727*4882a593Smuzhiyun 			struct v4l2_subdev_mbus_code_enum *code)
3728*4882a593Smuzhiyun {
3729*4882a593Smuzhiyun 	switch (code->index) {
3730*4882a593Smuzhiyun 	case 0:
3731*4882a593Smuzhiyun 		code->code = IT6616_MEDIA_BUS_FMT;
3732*4882a593Smuzhiyun 		break;
3733*4882a593Smuzhiyun 
3734*4882a593Smuzhiyun 	default:
3735*4882a593Smuzhiyun 		return -EINVAL;
3736*4882a593Smuzhiyun 	}
3737*4882a593Smuzhiyun 
3738*4882a593Smuzhiyun 	return 0;
3739*4882a593Smuzhiyun }
3740*4882a593Smuzhiyun 
it6616_enum_frame_sizes(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)3741*4882a593Smuzhiyun static int it6616_enum_frame_sizes(struct v4l2_subdev *sd,
3742*4882a593Smuzhiyun 				   struct v4l2_subdev_pad_config *cfg,
3743*4882a593Smuzhiyun 				   struct v4l2_subdev_frame_size_enum *fse)
3744*4882a593Smuzhiyun {
3745*4882a593Smuzhiyun 	if (fse->index >= ARRAY_SIZE(supported_modes))
3746*4882a593Smuzhiyun 		return -EINVAL;
3747*4882a593Smuzhiyun 
3748*4882a593Smuzhiyun 	if (fse->code != IT6616_MEDIA_BUS_FMT)
3749*4882a593Smuzhiyun 		return -EINVAL;
3750*4882a593Smuzhiyun 
3751*4882a593Smuzhiyun 	fse->min_width  = supported_modes[fse->index].width;
3752*4882a593Smuzhiyun 	fse->max_width  = supported_modes[fse->index].width;
3753*4882a593Smuzhiyun 	fse->max_height = supported_modes[fse->index].height;
3754*4882a593Smuzhiyun 	fse->min_height = supported_modes[fse->index].height;
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun 	return 0;
3757*4882a593Smuzhiyun }
3758*4882a593Smuzhiyun 
it6616_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)3759*4882a593Smuzhiyun static int it6616_get_fmt(struct v4l2_subdev *sd,
3760*4882a593Smuzhiyun 			struct v4l2_subdev_pad_config *cfg,
3761*4882a593Smuzhiyun 			struct v4l2_subdev_format *format)
3762*4882a593Smuzhiyun {
3763*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3764*4882a593Smuzhiyun 
3765*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3766*4882a593Smuzhiyun 	format->format.code = it6616->mbus_fmt_code;
3767*4882a593Smuzhiyun 	format->format.width = it6616->timings.bt.width;
3768*4882a593Smuzhiyun 	format->format.height = it6616->timings.bt.height;
3769*4882a593Smuzhiyun 	format->format.field =
3770*4882a593Smuzhiyun 		it6616->timings.bt.interlaced ?
3771*4882a593Smuzhiyun 		V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
3772*4882a593Smuzhiyun 	format->format.colorspace = V4L2_COLORSPACE_SRGB;
3773*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3774*4882a593Smuzhiyun 
3775*4882a593Smuzhiyun 	v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field code:%d\n",
3776*4882a593Smuzhiyun 			__func__, format->format.code, format->format.width,
3777*4882a593Smuzhiyun 			format->format.height, format->format.field);
3778*4882a593Smuzhiyun 
3779*4882a593Smuzhiyun 	return 0;
3780*4882a593Smuzhiyun }
3781*4882a593Smuzhiyun 
it6616_enum_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_interval_enum * fie)3782*4882a593Smuzhiyun static int it6616_enum_frame_interval(struct v4l2_subdev *sd,
3783*4882a593Smuzhiyun 				struct v4l2_subdev_pad_config *cfg,
3784*4882a593Smuzhiyun 				struct v4l2_subdev_frame_interval_enum *fie)
3785*4882a593Smuzhiyun {
3786*4882a593Smuzhiyun 	if (fie->index >= ARRAY_SIZE(supported_modes))
3787*4882a593Smuzhiyun 		return -EINVAL;
3788*4882a593Smuzhiyun 
3789*4882a593Smuzhiyun 	fie->code = IT6616_MEDIA_BUS_FMT;
3790*4882a593Smuzhiyun 
3791*4882a593Smuzhiyun 	fie->width = supported_modes[fie->index].width;
3792*4882a593Smuzhiyun 	fie->height = supported_modes[fie->index].height;
3793*4882a593Smuzhiyun 	fie->interval = supported_modes[fie->index].max_fps;
3794*4882a593Smuzhiyun 
3795*4882a593Smuzhiyun 	return 0;
3796*4882a593Smuzhiyun }
3797*4882a593Smuzhiyun 
it6616_get_reso_dist(const struct it6616_mode * mode,struct v4l2_mbus_framefmt * framefmt)3798*4882a593Smuzhiyun static int it6616_get_reso_dist(const struct it6616_mode *mode,
3799*4882a593Smuzhiyun 				struct v4l2_mbus_framefmt *framefmt)
3800*4882a593Smuzhiyun {
3801*4882a593Smuzhiyun 	return abs(mode->width - framefmt->width) +
3802*4882a593Smuzhiyun 		abs(mode->height - framefmt->height);
3803*4882a593Smuzhiyun }
3804*4882a593Smuzhiyun 
3805*4882a593Smuzhiyun static const struct it6616_mode *
it6616_find_best_fit(struct v4l2_subdev_format * fmt)3806*4882a593Smuzhiyun it6616_find_best_fit(struct v4l2_subdev_format *fmt)
3807*4882a593Smuzhiyun {
3808*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
3809*4882a593Smuzhiyun 	int dist;
3810*4882a593Smuzhiyun 	int cur_best_fit = 0;
3811*4882a593Smuzhiyun 	int cur_best_fit_dist = -1;
3812*4882a593Smuzhiyun 	unsigned int i;
3813*4882a593Smuzhiyun 
3814*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
3815*4882a593Smuzhiyun 		dist = it6616_get_reso_dist(&supported_modes[i], framefmt);
3816*4882a593Smuzhiyun 		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
3817*4882a593Smuzhiyun 			cur_best_fit_dist = dist;
3818*4882a593Smuzhiyun 			cur_best_fit = i;
3819*4882a593Smuzhiyun 		}
3820*4882a593Smuzhiyun 	}
3821*4882a593Smuzhiyun 
3822*4882a593Smuzhiyun 	return &supported_modes[cur_best_fit];
3823*4882a593Smuzhiyun }
3824*4882a593Smuzhiyun 
it6616_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)3825*4882a593Smuzhiyun static int it6616_set_fmt(struct v4l2_subdev *sd,
3826*4882a593Smuzhiyun 			struct v4l2_subdev_pad_config *cfg,
3827*4882a593Smuzhiyun 			struct v4l2_subdev_format *format)
3828*4882a593Smuzhiyun {
3829*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3830*4882a593Smuzhiyun 	const struct it6616_mode *mode;
3831*4882a593Smuzhiyun 
3832*4882a593Smuzhiyun 	/* is overwritten by get_fmt */
3833*4882a593Smuzhiyun 	u32 code = format->format.code;
3834*4882a593Smuzhiyun 	int ret = it6616_get_fmt(sd, cfg, format);
3835*4882a593Smuzhiyun 
3836*4882a593Smuzhiyun 	format->format.code = code;
3837*4882a593Smuzhiyun 
3838*4882a593Smuzhiyun 	if (ret)
3839*4882a593Smuzhiyun 		return ret;
3840*4882a593Smuzhiyun 
3841*4882a593Smuzhiyun 	switch (code) {
3842*4882a593Smuzhiyun 	case IT6616_MEDIA_BUS_FMT:
3843*4882a593Smuzhiyun 		break;
3844*4882a593Smuzhiyun 
3845*4882a593Smuzhiyun 	default:
3846*4882a593Smuzhiyun 		return -EINVAL;
3847*4882a593Smuzhiyun 	}
3848*4882a593Smuzhiyun 
3849*4882a593Smuzhiyun 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
3850*4882a593Smuzhiyun 		return 0;
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun 	it6616->mbus_fmt_code = format->format.code;
3853*4882a593Smuzhiyun 	mode = it6616_find_best_fit(format);
3854*4882a593Smuzhiyun 	it6616->cur_mode = mode;
3855*4882a593Smuzhiyun 
3856*4882a593Smuzhiyun 	return 0;
3857*4882a593Smuzhiyun }
3858*4882a593Smuzhiyun 
it6616_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)3859*4882a593Smuzhiyun static int it6616_g_frame_interval(struct v4l2_subdev *sd,
3860*4882a593Smuzhiyun 			struct v4l2_subdev_frame_interval *fi)
3861*4882a593Smuzhiyun {
3862*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3863*4882a593Smuzhiyun 	const struct it6616_mode *mode = it6616->cur_mode;
3864*4882a593Smuzhiyun 
3865*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3866*4882a593Smuzhiyun 	fi->interval = mode->max_fps;
3867*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3868*4882a593Smuzhiyun 
3869*4882a593Smuzhiyun 	return 0;
3870*4882a593Smuzhiyun }
3871*4882a593Smuzhiyun 
it6616_get_module_inf(struct it6616 * it6616,struct rkmodule_inf * inf)3872*4882a593Smuzhiyun static void it6616_get_module_inf(struct it6616 *it6616,
3873*4882a593Smuzhiyun 				  struct rkmodule_inf *inf)
3874*4882a593Smuzhiyun {
3875*4882a593Smuzhiyun 	memset(inf, 0, sizeof(*inf));
3876*4882a593Smuzhiyun 	strscpy(inf->base.sensor, IT6616_NAME, sizeof(inf->base.sensor));
3877*4882a593Smuzhiyun 	strscpy(inf->base.module, it6616->module_name, sizeof(inf->base.module));
3878*4882a593Smuzhiyun 	strscpy(inf->base.lens, it6616->len_name, sizeof(inf->base.lens));
3879*4882a593Smuzhiyun }
3880*4882a593Smuzhiyun 
it6616_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)3881*4882a593Smuzhiyun static long it6616_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
3882*4882a593Smuzhiyun {
3883*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3884*4882a593Smuzhiyun 	long ret = 0;
3885*4882a593Smuzhiyun 
3886*4882a593Smuzhiyun 	switch (cmd) {
3887*4882a593Smuzhiyun 	case RKMODULE_GET_MODULE_INFO:
3888*4882a593Smuzhiyun 		it6616_get_module_inf(it6616, (struct rkmodule_inf *)arg);
3889*4882a593Smuzhiyun 		break;
3890*4882a593Smuzhiyun 	case RKMODULE_GET_HDMI_MODE:
3891*4882a593Smuzhiyun 		*(int *)arg = RKMODULE_HDMIIN_MODE;
3892*4882a593Smuzhiyun 		break;
3893*4882a593Smuzhiyun 	default:
3894*4882a593Smuzhiyun 		ret = -ENOIOCTLCMD;
3895*4882a593Smuzhiyun 		break;
3896*4882a593Smuzhiyun 	}
3897*4882a593Smuzhiyun 
3898*4882a593Smuzhiyun 	return ret;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun 
it6616_s_power(struct v4l2_subdev * sd,int on)3901*4882a593Smuzhiyun static int it6616_s_power(struct v4l2_subdev *sd, int on)
3902*4882a593Smuzhiyun {
3903*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3904*4882a593Smuzhiyun 	int ret = 0;
3905*4882a593Smuzhiyun 
3906*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3907*4882a593Smuzhiyun 
3908*4882a593Smuzhiyun 	if (it6616->power_on == !!on)
3909*4882a593Smuzhiyun 		goto unlock_and_return;
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun 	if (on)
3912*4882a593Smuzhiyun 		it6616->power_on = true;
3913*4882a593Smuzhiyun 	else
3914*4882a593Smuzhiyun 		it6616->power_on = false;
3915*4882a593Smuzhiyun 
3916*4882a593Smuzhiyun unlock_and_return:
3917*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3918*4882a593Smuzhiyun 
3919*4882a593Smuzhiyun 	return ret;
3920*4882a593Smuzhiyun }
3921*4882a593Smuzhiyun 
3922*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
it6616_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)3923*4882a593Smuzhiyun static long it6616_compat_ioctl32(struct v4l2_subdev *sd,
3924*4882a593Smuzhiyun 				  unsigned int cmd, unsigned long arg)
3925*4882a593Smuzhiyun {
3926*4882a593Smuzhiyun 	void __user *up = compat_ptr(arg);
3927*4882a593Smuzhiyun 	struct rkmodule_inf *inf;
3928*4882a593Smuzhiyun 	long ret;
3929*4882a593Smuzhiyun 	int *seq;
3930*4882a593Smuzhiyun 
3931*4882a593Smuzhiyun 	switch (cmd) {
3932*4882a593Smuzhiyun 	case RKMODULE_GET_MODULE_INFO:
3933*4882a593Smuzhiyun 		inf = kzalloc(sizeof(*inf), GFP_KERNEL);
3934*4882a593Smuzhiyun 		if (!inf) {
3935*4882a593Smuzhiyun 			ret = -ENOMEM;
3936*4882a593Smuzhiyun 			return ret;
3937*4882a593Smuzhiyun 		}
3938*4882a593Smuzhiyun 
3939*4882a593Smuzhiyun 		ret = it6616_ioctl(sd, cmd, inf);
3940*4882a593Smuzhiyun 		if (!ret) {
3941*4882a593Smuzhiyun 			ret = copy_to_user(up, inf, sizeof(*inf));
3942*4882a593Smuzhiyun 			if (ret)
3943*4882a593Smuzhiyun 				ret = -EFAULT;
3944*4882a593Smuzhiyun 		}
3945*4882a593Smuzhiyun 		kfree(inf);
3946*4882a593Smuzhiyun 		break;
3947*4882a593Smuzhiyun 	case RKMODULE_GET_HDMI_MODE:
3948*4882a593Smuzhiyun 		seq = kzalloc(sizeof(*seq), GFP_KERNEL);
3949*4882a593Smuzhiyun 		if (!seq) {
3950*4882a593Smuzhiyun 			ret = -ENOMEM;
3951*4882a593Smuzhiyun 			return ret;
3952*4882a593Smuzhiyun 		}
3953*4882a593Smuzhiyun 
3954*4882a593Smuzhiyun 		ret = it6616_ioctl(sd, cmd, seq);
3955*4882a593Smuzhiyun 		if (!ret) {
3956*4882a593Smuzhiyun 			ret = copy_to_user(up, seq, sizeof(*seq));
3957*4882a593Smuzhiyun 			if (ret)
3958*4882a593Smuzhiyun 				ret = -EFAULT;
3959*4882a593Smuzhiyun 		}
3960*4882a593Smuzhiyun 		kfree(seq);
3961*4882a593Smuzhiyun 		break;
3962*4882a593Smuzhiyun 	default:
3963*4882a593Smuzhiyun 		ret = -ENOIOCTLCMD;
3964*4882a593Smuzhiyun 		break;
3965*4882a593Smuzhiyun 	}
3966*4882a593Smuzhiyun 
3967*4882a593Smuzhiyun 	return ret;
3968*4882a593Smuzhiyun }
3969*4882a593Smuzhiyun #endif
3970*4882a593Smuzhiyun 
3971*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
it6616_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)3972*4882a593Smuzhiyun static int it6616_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
3973*4882a593Smuzhiyun {
3974*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
3975*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *try_fmt =
3976*4882a593Smuzhiyun 				v4l2_subdev_get_try_format(sd, fh->pad, 0);
3977*4882a593Smuzhiyun 	const struct it6616_mode *def_mode = &supported_modes[0];
3978*4882a593Smuzhiyun 
3979*4882a593Smuzhiyun 	mutex_lock(&it6616->confctl_mutex);
3980*4882a593Smuzhiyun 	/* Initialize try_fmt */
3981*4882a593Smuzhiyun 	try_fmt->width = def_mode->width;
3982*4882a593Smuzhiyun 	try_fmt->height = def_mode->height;
3983*4882a593Smuzhiyun 	try_fmt->code = IT6616_MEDIA_BUS_FMT;
3984*4882a593Smuzhiyun 	try_fmt->field = V4L2_FIELD_NONE;
3985*4882a593Smuzhiyun 	mutex_unlock(&it6616->confctl_mutex);
3986*4882a593Smuzhiyun 
3987*4882a593Smuzhiyun 	return 0;
3988*4882a593Smuzhiyun }
3989*4882a593Smuzhiyun #endif
3990*4882a593Smuzhiyun 
3991*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
3992*4882a593Smuzhiyun static const struct v4l2_subdev_internal_ops it6616_internal_ops = {
3993*4882a593Smuzhiyun 	.open = it6616_open,
3994*4882a593Smuzhiyun };
3995*4882a593Smuzhiyun #endif
3996*4882a593Smuzhiyun 
3997*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops it6616_core_ops = {
3998*4882a593Smuzhiyun 	.s_power = it6616_s_power,
3999*4882a593Smuzhiyun 	.interrupt_service_routine = it6616_isr,
4000*4882a593Smuzhiyun 	.subscribe_event = it6616_subscribe_event,
4001*4882a593Smuzhiyun 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
4002*4882a593Smuzhiyun 	.ioctl = it6616_ioctl,
4003*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
4004*4882a593Smuzhiyun 	.compat_ioctl32 = it6616_compat_ioctl32,
4005*4882a593Smuzhiyun #endif
4006*4882a593Smuzhiyun };
4007*4882a593Smuzhiyun 
4008*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops it6616_video_ops = {
4009*4882a593Smuzhiyun 	.g_input_status = it6616_g_input_status,
4010*4882a593Smuzhiyun 	.s_dv_timings = it6616_s_dv_timings,
4011*4882a593Smuzhiyun 	.g_dv_timings = it6616_g_dv_timings,
4012*4882a593Smuzhiyun 	.query_dv_timings = it6616_query_dv_timings,
4013*4882a593Smuzhiyun 	.s_stream = it6616_s_stream,
4014*4882a593Smuzhiyun 	.g_frame_interval = it6616_g_frame_interval,
4015*4882a593Smuzhiyun };
4016*4882a593Smuzhiyun 
4017*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops it6616_pad_ops = {
4018*4882a593Smuzhiyun 	.enum_mbus_code = it6616_enum_mbus_code,
4019*4882a593Smuzhiyun 	.enum_frame_size = it6616_enum_frame_sizes,
4020*4882a593Smuzhiyun 	.enum_frame_interval = it6616_enum_frame_interval,
4021*4882a593Smuzhiyun 	.set_fmt = it6616_set_fmt,
4022*4882a593Smuzhiyun 	.get_fmt = it6616_get_fmt,
4023*4882a593Smuzhiyun 	.enum_dv_timings = it6616_enum_dv_timings,
4024*4882a593Smuzhiyun 	.dv_timings_cap = it6616_dv_timings_cap,
4025*4882a593Smuzhiyun 	.get_mbus_config = it6616_g_mbus_config,
4026*4882a593Smuzhiyun };
4027*4882a593Smuzhiyun 
4028*4882a593Smuzhiyun static const struct v4l2_subdev_ops it6616_ops = {
4029*4882a593Smuzhiyun 	.core = &it6616_core_ops,
4030*4882a593Smuzhiyun 	.video = &it6616_video_ops,
4031*4882a593Smuzhiyun 	.pad = &it6616_pad_ops,
4032*4882a593Smuzhiyun };
4033*4882a593Smuzhiyun 
4034*4882a593Smuzhiyun static const struct v4l2_ctrl_config it6616_ctrl_audio_sampling_rate = {
4035*4882a593Smuzhiyun 	.id = RK_V4L2_CID_AUDIO_SAMPLING_RATE,
4036*4882a593Smuzhiyun 	.name = "Audio sampling rate",
4037*4882a593Smuzhiyun 	.type = V4L2_CTRL_TYPE_INTEGER,
4038*4882a593Smuzhiyun 	.min = 0,
4039*4882a593Smuzhiyun 	.max = 768000,
4040*4882a593Smuzhiyun 	.step = 1,
4041*4882a593Smuzhiyun 	.def = 0,
4042*4882a593Smuzhiyun 	.flags = V4L2_CTRL_FLAG_READ_ONLY,
4043*4882a593Smuzhiyun };
4044*4882a593Smuzhiyun 
4045*4882a593Smuzhiyun static const struct v4l2_ctrl_config it6616_ctrl_audio_present = {
4046*4882a593Smuzhiyun 	.id = RK_V4L2_CID_AUDIO_PRESENT,
4047*4882a593Smuzhiyun 	.name = "Audio present",
4048*4882a593Smuzhiyun 	.type = V4L2_CTRL_TYPE_BOOLEAN,
4049*4882a593Smuzhiyun 	.min = 0,
4050*4882a593Smuzhiyun 	.max = 1,
4051*4882a593Smuzhiyun 	.step = 1,
4052*4882a593Smuzhiyun 	.def = 0,
4053*4882a593Smuzhiyun 	.flags = V4L2_CTRL_FLAG_READ_ONLY,
4054*4882a593Smuzhiyun };
4055*4882a593Smuzhiyun 
it6616_reset(struct it6616 * it6616)4056*4882a593Smuzhiyun static void it6616_reset(struct it6616 *it6616)
4057*4882a593Smuzhiyun {
4058*4882a593Smuzhiyun 	gpiod_set_value(it6616->reset_gpio, 0);
4059*4882a593Smuzhiyun 	usleep_range(2000, 2100);
4060*4882a593Smuzhiyun 	gpiod_set_value(it6616->reset_gpio, 1);
4061*4882a593Smuzhiyun 	usleep_range(120*1000, 121*1000);
4062*4882a593Smuzhiyun 	gpiod_set_value(it6616->reset_gpio, 0);
4063*4882a593Smuzhiyun 	usleep_range(300*1000, 310*1000);
4064*4882a593Smuzhiyun }
4065*4882a593Smuzhiyun 
it6616_init_v4l2_ctrls(struct it6616 * it6616)4066*4882a593Smuzhiyun static int it6616_init_v4l2_ctrls(struct it6616 *it6616)
4067*4882a593Smuzhiyun {
4068*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
4069*4882a593Smuzhiyun 	int ret;
4070*4882a593Smuzhiyun 
4071*4882a593Smuzhiyun 	sd = &it6616->sd;
4072*4882a593Smuzhiyun 	ret = v4l2_ctrl_handler_init(&it6616->hdl, 5);
4073*4882a593Smuzhiyun 	if (ret)
4074*4882a593Smuzhiyun 		return ret;
4075*4882a593Smuzhiyun 
4076*4882a593Smuzhiyun 	it6616->link_freq = v4l2_ctrl_new_int_menu(&it6616->hdl, NULL,
4077*4882a593Smuzhiyun 			V4L2_CID_LINK_FREQ,
4078*4882a593Smuzhiyun 			ARRAY_SIZE(link_freq_menu_items) - 1, 0,
4079*4882a593Smuzhiyun 			link_freq_menu_items);
4080*4882a593Smuzhiyun 	it6616->pixel_rate = v4l2_ctrl_new_std(&it6616->hdl, NULL,
4081*4882a593Smuzhiyun 			V4L2_CID_PIXEL_RATE,
4082*4882a593Smuzhiyun 			0, IT6616_PIXEL_RATE, 1, IT6616_PIXEL_RATE);
4083*4882a593Smuzhiyun 
4084*4882a593Smuzhiyun 	it6616->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&it6616->hdl,
4085*4882a593Smuzhiyun 			NULL, V4L2_CID_DV_RX_POWER_PRESENT,
4086*4882a593Smuzhiyun 			0, 1, 0, 0);
4087*4882a593Smuzhiyun 
4088*4882a593Smuzhiyun 	it6616->audio_sampling_rate_ctrl =
4089*4882a593Smuzhiyun 		v4l2_ctrl_new_custom(&it6616->hdl,
4090*4882a593Smuzhiyun 				&it6616_ctrl_audio_sampling_rate, NULL);
4091*4882a593Smuzhiyun 	it6616->audio_present_ctrl = v4l2_ctrl_new_custom(&it6616->hdl,
4092*4882a593Smuzhiyun 			&it6616_ctrl_audio_present, NULL);
4093*4882a593Smuzhiyun 
4094*4882a593Smuzhiyun 	sd->ctrl_handler = &it6616->hdl;
4095*4882a593Smuzhiyun 	if (it6616->hdl.error) {
4096*4882a593Smuzhiyun 		ret = it6616->hdl.error;
4097*4882a593Smuzhiyun 		v4l2_err(sd, "cfg v4l2 ctrls failed! ret:%d\n", ret);
4098*4882a593Smuzhiyun 		return ret;
4099*4882a593Smuzhiyun 	}
4100*4882a593Smuzhiyun 
4101*4882a593Smuzhiyun 	__v4l2_ctrl_s_ctrl(it6616->link_freq, link_freq_menu_items[0]);
4102*4882a593Smuzhiyun 	__v4l2_ctrl_s_ctrl_int64(it6616->pixel_rate, IT6616_PIXEL_RATE);
4103*4882a593Smuzhiyun 
4104*4882a593Smuzhiyun 	if (it6616_update_controls(sd)) {
4105*4882a593Smuzhiyun 		ret = -ENODEV;
4106*4882a593Smuzhiyun 		v4l2_err(sd, "update v4l2 ctrls failed! ret:%d\n", ret);
4107*4882a593Smuzhiyun 		return ret;
4108*4882a593Smuzhiyun 	}
4109*4882a593Smuzhiyun 
4110*4882a593Smuzhiyun 	return 0;
4111*4882a593Smuzhiyun }
4112*4882a593Smuzhiyun 
4113*4882a593Smuzhiyun #ifdef CONFIG_OF
it6616_probe_of(struct it6616 * it6616)4114*4882a593Smuzhiyun static int it6616_probe_of(struct it6616 *it6616)
4115*4882a593Smuzhiyun {
4116*4882a593Smuzhiyun 	struct device *dev = &it6616->i2c_client->dev;
4117*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
4118*4882a593Smuzhiyun 	struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
4119*4882a593Smuzhiyun 	struct device_node *ep;
4120*4882a593Smuzhiyun 	int ret;
4121*4882a593Smuzhiyun 
4122*4882a593Smuzhiyun 	ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
4123*4882a593Smuzhiyun 			&it6616->module_index);
4124*4882a593Smuzhiyun 	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
4125*4882a593Smuzhiyun 			&it6616->module_facing);
4126*4882a593Smuzhiyun 	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
4127*4882a593Smuzhiyun 			&it6616->module_name);
4128*4882a593Smuzhiyun 	ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
4129*4882a593Smuzhiyun 			&it6616->len_name);
4130*4882a593Smuzhiyun 	if (ret) {
4131*4882a593Smuzhiyun 		dev_err(dev, "could not get module information!\n");
4132*4882a593Smuzhiyun 		return -EINVAL;
4133*4882a593Smuzhiyun 	}
4134*4882a593Smuzhiyun 
4135*4882a593Smuzhiyun 	it6616->power_gpio = devm_gpiod_get_optional(dev, "power",
4136*4882a593Smuzhiyun 			GPIOD_OUT_LOW);
4137*4882a593Smuzhiyun 	if (IS_ERR(it6616->power_gpio)) {
4138*4882a593Smuzhiyun 		dev_err(dev, "failed to get power gpio\n");
4139*4882a593Smuzhiyun 		ret = PTR_ERR(it6616->power_gpio);
4140*4882a593Smuzhiyun 		return ret;
4141*4882a593Smuzhiyun 	}
4142*4882a593Smuzhiyun 
4143*4882a593Smuzhiyun 	it6616->reset_gpio = devm_gpiod_get_optional(dev, "reset",
4144*4882a593Smuzhiyun 			GPIOD_OUT_HIGH);
4145*4882a593Smuzhiyun 	if (IS_ERR(it6616->reset_gpio)) {
4146*4882a593Smuzhiyun 		dev_err(dev, "failed to get reset gpio\n");
4147*4882a593Smuzhiyun 		ret = PTR_ERR(it6616->reset_gpio);
4148*4882a593Smuzhiyun 		return ret;
4149*4882a593Smuzhiyun 	}
4150*4882a593Smuzhiyun 
4151*4882a593Smuzhiyun 	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
4152*4882a593Smuzhiyun 	if (!ep) {
4153*4882a593Smuzhiyun 		dev_err(dev, "missing endpoint node\n");
4154*4882a593Smuzhiyun 		return -EINVAL;
4155*4882a593Smuzhiyun 	}
4156*4882a593Smuzhiyun 
4157*4882a593Smuzhiyun 	ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
4158*4882a593Smuzhiyun 	if (ret) {
4159*4882a593Smuzhiyun 		dev_err(dev, "failed to parse endpoint\n");
4160*4882a593Smuzhiyun 		goto put_node;
4161*4882a593Smuzhiyun 	}
4162*4882a593Smuzhiyun 
4163*4882a593Smuzhiyun 	if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY ||
4164*4882a593Smuzhiyun 			endpoint.bus.mipi_csi2.num_data_lanes == 0) {
4165*4882a593Smuzhiyun 		dev_err(dev, "missing CSI-2 properties in endpoint\n");
4166*4882a593Smuzhiyun 		ret = -EINVAL;
4167*4882a593Smuzhiyun 		goto free_endpoint;
4168*4882a593Smuzhiyun 	}
4169*4882a593Smuzhiyun 
4170*4882a593Smuzhiyun 	it6616->xvclk = devm_clk_get(dev, "xvclk");
4171*4882a593Smuzhiyun 	if (IS_ERR(it6616->xvclk)) {
4172*4882a593Smuzhiyun 		dev_err(dev, "failed to get xvclk\n");
4173*4882a593Smuzhiyun 		ret = -EINVAL;
4174*4882a593Smuzhiyun 		goto free_endpoint;
4175*4882a593Smuzhiyun 	}
4176*4882a593Smuzhiyun 
4177*4882a593Smuzhiyun 	ret = clk_prepare_enable(it6616->xvclk);
4178*4882a593Smuzhiyun 	if (ret) {
4179*4882a593Smuzhiyun 		dev_err(dev, "Failed! to enable xvclk\n");
4180*4882a593Smuzhiyun 		goto free_endpoint;
4181*4882a593Smuzhiyun 	}
4182*4882a593Smuzhiyun 
4183*4882a593Smuzhiyun 	it6616->csi_lanes_in_use = endpoint.bus.mipi_csi2.num_data_lanes;
4184*4882a593Smuzhiyun 	it6616->bus = endpoint.bus.mipi_csi2;
4185*4882a593Smuzhiyun 
4186*4882a593Smuzhiyun 	gpiod_set_value(it6616->power_gpio, 1);
4187*4882a593Smuzhiyun 	it6616_reset(it6616);
4188*4882a593Smuzhiyun 
4189*4882a593Smuzhiyun 	ret = 0;
4190*4882a593Smuzhiyun 
4191*4882a593Smuzhiyun free_endpoint:
4192*4882a593Smuzhiyun 	v4l2_fwnode_endpoint_free(&endpoint);
4193*4882a593Smuzhiyun put_node:
4194*4882a593Smuzhiyun 	of_node_put(ep);
4195*4882a593Smuzhiyun 	return ret;
4196*4882a593Smuzhiyun }
4197*4882a593Smuzhiyun #else
it6616_probe_of(struct it6616 * state)4198*4882a593Smuzhiyun static inline int it6616_probe_of(struct it6616 *state)
4199*4882a593Smuzhiyun {
4200*4882a593Smuzhiyun 	return -ENODEV;
4201*4882a593Smuzhiyun }
4202*4882a593Smuzhiyun #endif
4203*4882a593Smuzhiyun 
audio_present_show(struct device * dev,struct device_attribute * attr,char * buf)4204*4882a593Smuzhiyun static ssize_t audio_present_show(struct device *dev,
4205*4882a593Smuzhiyun 				      struct device_attribute *attr, char *buf)
4206*4882a593Smuzhiyun {
4207*4882a593Smuzhiyun 	struct it6616 *it6616 = g_it6616;
4208*4882a593Smuzhiyun 
4209*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n",
4210*4882a593Smuzhiyun 			tx_5v_power_present(&it6616->sd) ? 1 : 0);
4211*4882a593Smuzhiyun }
4212*4882a593Smuzhiyun 
audio_rate_show(struct device * dev,struct device_attribute * attr,char * buf)4213*4882a593Smuzhiyun static ssize_t audio_rate_show(struct device *dev,
4214*4882a593Smuzhiyun 				      struct device_attribute *attr, char *buf)
4215*4882a593Smuzhiyun {
4216*4882a593Smuzhiyun 	struct it6616 *it6616 = g_it6616;
4217*4882a593Smuzhiyun 
4218*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n",
4219*4882a593Smuzhiyun 			code_to_rate_table[it6616->ainfo.force_sample_freq]);
4220*4882a593Smuzhiyun }
4221*4882a593Smuzhiyun 
4222*4882a593Smuzhiyun static DEVICE_ATTR_RO(audio_present);
4223*4882a593Smuzhiyun static DEVICE_ATTR_RO(audio_rate);
4224*4882a593Smuzhiyun 
it6616_create_class_attr(struct it6616 * it6616)4225*4882a593Smuzhiyun static int it6616_create_class_attr(struct it6616 *it6616)
4226*4882a593Smuzhiyun {
4227*4882a593Smuzhiyun 	int ret = 0;
4228*4882a593Smuzhiyun 
4229*4882a593Smuzhiyun 	it6616->hdmirx_class = class_create(THIS_MODULE, "hdmirx_it6616");
4230*4882a593Smuzhiyun 	if (IS_ERR(it6616->hdmirx_class)) {
4231*4882a593Smuzhiyun 		ret = -ENOMEM;
4232*4882a593Smuzhiyun 		dev_err(it6616->dev, "failed to create hdmirx_it6616 class!\n");
4233*4882a593Smuzhiyun 		return ret;
4234*4882a593Smuzhiyun 	}
4235*4882a593Smuzhiyun 
4236*4882a593Smuzhiyun 	it6616->classdev = device_create(it6616->hdmirx_class, NULL,
4237*4882a593Smuzhiyun 					MKDEV(0, 0), NULL, "hdmirx_it6616");
4238*4882a593Smuzhiyun 	if (IS_ERR(it6616->classdev)) {
4239*4882a593Smuzhiyun 		ret = PTR_ERR(it6616->classdev);
4240*4882a593Smuzhiyun 		dev_err(it6616->dev, "Failed to create device\n");
4241*4882a593Smuzhiyun 		goto err1;
4242*4882a593Smuzhiyun 	}
4243*4882a593Smuzhiyun 
4244*4882a593Smuzhiyun 	ret = device_create_file(it6616->classdev,
4245*4882a593Smuzhiyun 				&dev_attr_audio_present);
4246*4882a593Smuzhiyun 	if (ret) {
4247*4882a593Smuzhiyun 		dev_err(it6616->dev, "failed to create attr audio_present!\n");
4248*4882a593Smuzhiyun 		goto err1;
4249*4882a593Smuzhiyun 	}
4250*4882a593Smuzhiyun 
4251*4882a593Smuzhiyun 	ret = device_create_file(it6616->classdev,
4252*4882a593Smuzhiyun 				&dev_attr_audio_rate);
4253*4882a593Smuzhiyun 	if (ret) {
4254*4882a593Smuzhiyun 		dev_err(it6616->dev,
4255*4882a593Smuzhiyun 			"failed to create attr audio_rate!\n");
4256*4882a593Smuzhiyun 		goto err;
4257*4882a593Smuzhiyun 	}
4258*4882a593Smuzhiyun 
4259*4882a593Smuzhiyun 	return ret;
4260*4882a593Smuzhiyun 
4261*4882a593Smuzhiyun err:
4262*4882a593Smuzhiyun 	device_remove_file(it6616->classdev, &dev_attr_audio_present);
4263*4882a593Smuzhiyun err1:
4264*4882a593Smuzhiyun 	class_destroy(it6616->hdmirx_class);
4265*4882a593Smuzhiyun 	return ret;
4266*4882a593Smuzhiyun }
4267*4882a593Smuzhiyun 
it6616_remove_class_attr(struct it6616 * it6616)4268*4882a593Smuzhiyun static void it6616_remove_class_attr(struct it6616 *it6616)
4269*4882a593Smuzhiyun {
4270*4882a593Smuzhiyun 	device_remove_file(it6616->classdev, &dev_attr_audio_rate);
4271*4882a593Smuzhiyun 	device_remove_file(it6616->classdev, &dev_attr_audio_present);
4272*4882a593Smuzhiyun 	class_destroy(it6616->hdmirx_class);
4273*4882a593Smuzhiyun }
4274*4882a593Smuzhiyun 
it6616_probe(struct i2c_client * client,const struct i2c_device_id * id)4275*4882a593Smuzhiyun static int it6616_probe(struct i2c_client *client,
4276*4882a593Smuzhiyun 			  const struct i2c_device_id *id)
4277*4882a593Smuzhiyun {
4278*4882a593Smuzhiyun 	struct it6616 *it6616;
4279*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
4280*4882a593Smuzhiyun 	struct device *dev = &client->dev;
4281*4882a593Smuzhiyun 	char facing[2];
4282*4882a593Smuzhiyun 	int err = 0;
4283*4882a593Smuzhiyun 
4284*4882a593Smuzhiyun 	dev_info(dev, "driver version: %02x.%02x.%02x",
4285*4882a593Smuzhiyun 		DRIVER_VERSION >> 16,
4286*4882a593Smuzhiyun 		(DRIVER_VERSION & 0xff00) >> 8,
4287*4882a593Smuzhiyun 		DRIVER_VERSION & 0x00ff);
4288*4882a593Smuzhiyun 
4289*4882a593Smuzhiyun 	it6616 = devm_kzalloc(dev, sizeof(struct it6616), GFP_KERNEL);
4290*4882a593Smuzhiyun 	if (!it6616)
4291*4882a593Smuzhiyun 		return -ENOMEM;
4292*4882a593Smuzhiyun 
4293*4882a593Smuzhiyun 	sd = &it6616->sd;
4294*4882a593Smuzhiyun 	it6616->hdmi_i2c = client;
4295*4882a593Smuzhiyun 	it6616->mipi_i2c = i2c_new_dummy_device(client->adapter,
4296*4882a593Smuzhiyun 						I2C_ADR_MIPI >> 1);
4297*4882a593Smuzhiyun 
4298*4882a593Smuzhiyun 	if (!it6616->mipi_i2c)
4299*4882a593Smuzhiyun 		return -EIO;
4300*4882a593Smuzhiyun 
4301*4882a593Smuzhiyun 	it6616->edid_i2c = i2c_new_dummy_device(client->adapter,
4302*4882a593Smuzhiyun 						I2C_ADR_EDID >> 1);
4303*4882a593Smuzhiyun 
4304*4882a593Smuzhiyun 	if (!it6616->edid_i2c)
4305*4882a593Smuzhiyun 		goto unregister_mipi_i2c;
4306*4882a593Smuzhiyun 
4307*4882a593Smuzhiyun 	it6616->hdmi_regmap = devm_regmap_init_i2c(client,
4308*4882a593Smuzhiyun 				&it6616_hdmi_regmap_config);
4309*4882a593Smuzhiyun 	if (IS_ERR(it6616->hdmi_i2c)) {
4310*4882a593Smuzhiyun 		err = PTR_ERR(it6616->hdmi_i2c);
4311*4882a593Smuzhiyun 		goto unregister_edid_i2c;
4312*4882a593Smuzhiyun 	}
4313*4882a593Smuzhiyun 
4314*4882a593Smuzhiyun 	it6616->mipi_regmap = devm_regmap_init_i2c(it6616->mipi_i2c,
4315*4882a593Smuzhiyun 						&it6616_mipi_regmap_config);
4316*4882a593Smuzhiyun 	if (IS_ERR(it6616->mipi_regmap)) {
4317*4882a593Smuzhiyun 		err = PTR_ERR(it6616->mipi_regmap);
4318*4882a593Smuzhiyun 		goto unregister_edid_i2c;
4319*4882a593Smuzhiyun 	}
4320*4882a593Smuzhiyun 
4321*4882a593Smuzhiyun 	it6616->edid_regmap = devm_regmap_init_i2c(it6616->edid_i2c,
4322*4882a593Smuzhiyun 						&it6616_edid_regmap_config);
4323*4882a593Smuzhiyun 	if (IS_ERR(it6616->edid_regmap)) {
4324*4882a593Smuzhiyun 		err = PTR_ERR(it6616->edid_regmap);
4325*4882a593Smuzhiyun 		goto unregister_edid_i2c;
4326*4882a593Smuzhiyun 	}
4327*4882a593Smuzhiyun 
4328*4882a593Smuzhiyun 	it6616->dev = dev;
4329*4882a593Smuzhiyun 	it6616->cur_mode = &supported_modes[0];
4330*4882a593Smuzhiyun 	it6616->i2c_client = client;
4331*4882a593Smuzhiyun 	it6616->mbus_fmt_code = IT6616_MEDIA_BUS_FMT;
4332*4882a593Smuzhiyun 	err = it6616_probe_of(it6616);
4333*4882a593Smuzhiyun 	if (err) {
4334*4882a593Smuzhiyun 		v4l2_err(sd, "it6616_parse_of failed! err:%d\n", err);
4335*4882a593Smuzhiyun 		return err;
4336*4882a593Smuzhiyun 	}
4337*4882a593Smuzhiyun 	it6616_reset(it6616);
4338*4882a593Smuzhiyun 
4339*4882a593Smuzhiyun 	mutex_init(&it6616->confctl_mutex);
4340*4882a593Smuzhiyun 
4341*4882a593Smuzhiyun 	err = it6616_initial(it6616);
4342*4882a593Smuzhiyun 	if (err) {
4343*4882a593Smuzhiyun 		dev_err(dev, "it6616_initial failed: %d", err);
4344*4882a593Smuzhiyun 		err = -ENODEV;
4345*4882a593Smuzhiyun 		goto unregister_edid_i2c;
4346*4882a593Smuzhiyun 	}
4347*4882a593Smuzhiyun 
4348*4882a593Smuzhiyun 	err = sysfs_create_files(&client->dev.kobj, it6616_attrs);
4349*4882a593Smuzhiyun 	if (err) {
4350*4882a593Smuzhiyun 		dev_err(dev, "sysfs_create_files failed: %d", err);
4351*4882a593Smuzhiyun 		goto unregister_edid_i2c;
4352*4882a593Smuzhiyun 	}
4353*4882a593Smuzhiyun 
4354*4882a593Smuzhiyun 	i2c_set_clientdata(client, it6616);
4355*4882a593Smuzhiyun 	usleep_range(3000, 6000);
4356*4882a593Smuzhiyun 
4357*4882a593Smuzhiyun 	err = it6616_init_v4l2_ctrls(it6616);
4358*4882a593Smuzhiyun 	if (err)
4359*4882a593Smuzhiyun 		goto err_free_hdl;
4360*4882a593Smuzhiyun 
4361*4882a593Smuzhiyun 	client->flags |= I2C_CLIENT_SCCB;
4362*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
4363*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &it6616_ops);
4364*4882a593Smuzhiyun 	sd->internal_ops = &it6616_internal_ops;
4365*4882a593Smuzhiyun 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
4366*4882a593Smuzhiyun #endif
4367*4882a593Smuzhiyun 
4368*4882a593Smuzhiyun #if defined(CONFIG_MEDIA_CONTROLLER)
4369*4882a593Smuzhiyun 	it6616->pad.flags = MEDIA_PAD_FL_SOURCE;
4370*4882a593Smuzhiyun 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
4371*4882a593Smuzhiyun 	err = media_entity_pads_init(&sd->entity, 1, &it6616->pad);
4372*4882a593Smuzhiyun 	if (err < 0) {
4373*4882a593Smuzhiyun 		v4l2_err(sd, "media entity init failed! err:%d\n", err);
4374*4882a593Smuzhiyun 		goto err_free_hdl;
4375*4882a593Smuzhiyun 	}
4376*4882a593Smuzhiyun #endif
4377*4882a593Smuzhiyun 	memset(facing, 0, sizeof(facing));
4378*4882a593Smuzhiyun 	if (strcmp(it6616->module_facing, "back") == 0)
4379*4882a593Smuzhiyun 		facing[0] = 'b';
4380*4882a593Smuzhiyun 	else
4381*4882a593Smuzhiyun 		facing[0] = 'f';
4382*4882a593Smuzhiyun 
4383*4882a593Smuzhiyun 	snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
4384*4882a593Smuzhiyun 		 it6616->module_index, facing,
4385*4882a593Smuzhiyun 		 IT6616_NAME, dev_name(sd->dev));
4386*4882a593Smuzhiyun 	err = v4l2_async_register_subdev_sensor_common(sd);
4387*4882a593Smuzhiyun 	if (err < 0) {
4388*4882a593Smuzhiyun 		v4l2_err(sd, "v4l2 register subdev failed! err:%d\n", err);
4389*4882a593Smuzhiyun 		goto err_clean_entity;
4390*4882a593Smuzhiyun 	}
4391*4882a593Smuzhiyun 
4392*4882a593Smuzhiyun 	err = it6616_create_class_attr(it6616);
4393*4882a593Smuzhiyun 	if (err) {
4394*4882a593Smuzhiyun 		dev_err(it6616->dev, "create class attr failed! err:%d\n", err);
4395*4882a593Smuzhiyun 		return -ENODEV;
4396*4882a593Smuzhiyun 	}
4397*4882a593Smuzhiyun 
4398*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&it6616->work_i2c_poll, it6616_work_i2c_poll);
4399*4882a593Smuzhiyun 	schedule_delayed_work(&it6616->work_i2c_poll, msecs_to_jiffies(500));
4400*4882a593Smuzhiyun 	err = v4l2_ctrl_handler_setup(sd->ctrl_handler);
4401*4882a593Smuzhiyun 	if (err) {
4402*4882a593Smuzhiyun 		v4l2_err(sd, "v4l2 ctrl handler setup failed! err:%d\n", err);
4403*4882a593Smuzhiyun 		goto err_work_queues;
4404*4882a593Smuzhiyun 	}
4405*4882a593Smuzhiyun 
4406*4882a593Smuzhiyun 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
4407*4882a593Smuzhiyun 			client->addr << 1, client->adapter->name);
4408*4882a593Smuzhiyun 	g_it6616 = it6616;
4409*4882a593Smuzhiyun 
4410*4882a593Smuzhiyun 	return 0;
4411*4882a593Smuzhiyun 
4412*4882a593Smuzhiyun err_work_queues:
4413*4882a593Smuzhiyun 	cancel_delayed_work_sync(&it6616->work_i2c_poll);
4414*4882a593Smuzhiyun err_clean_entity:
4415*4882a593Smuzhiyun #if defined(CONFIG_MEDIA_CONTROLLER)
4416*4882a593Smuzhiyun 	media_entity_cleanup(&sd->entity);
4417*4882a593Smuzhiyun #endif
4418*4882a593Smuzhiyun err_free_hdl:
4419*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&it6616->hdl);
4420*4882a593Smuzhiyun 	mutex_destroy(&it6616->confctl_mutex);
4421*4882a593Smuzhiyun unregister_edid_i2c:
4422*4882a593Smuzhiyun 	i2c_unregister_device(it6616->edid_i2c);
4423*4882a593Smuzhiyun unregister_mipi_i2c:
4424*4882a593Smuzhiyun 	i2c_unregister_device(it6616->mipi_i2c);
4425*4882a593Smuzhiyun 
4426*4882a593Smuzhiyun 	return err;
4427*4882a593Smuzhiyun }
4428*4882a593Smuzhiyun 
it6616_remove(struct i2c_client * client)4429*4882a593Smuzhiyun static int it6616_remove(struct i2c_client *client)
4430*4882a593Smuzhiyun {
4431*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
4432*4882a593Smuzhiyun 	struct it6616 *it6616 = to_it6616(sd);
4433*4882a593Smuzhiyun 
4434*4882a593Smuzhiyun 	cancel_delayed_work_sync(&it6616->work_i2c_poll);
4435*4882a593Smuzhiyun 	it6616_remove_class_attr(it6616);
4436*4882a593Smuzhiyun 	v4l2_async_unregister_subdev(sd);
4437*4882a593Smuzhiyun 	v4l2_device_unregister_subdev(sd);
4438*4882a593Smuzhiyun #if defined(CONFIG_MEDIA_CONTROLLER)
4439*4882a593Smuzhiyun 	media_entity_cleanup(&sd->entity);
4440*4882a593Smuzhiyun #endif
4441*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(&it6616->hdl);
4442*4882a593Smuzhiyun 	sysfs_remove_files(&client->dev.kobj, it6616_attrs);
4443*4882a593Smuzhiyun 	mutex_destroy(&it6616->confctl_mutex);
4444*4882a593Smuzhiyun 
4445*4882a593Smuzhiyun 	i2c_unregister_device(it6616->mipi_i2c);
4446*4882a593Smuzhiyun 	i2c_unregister_device(it6616->edid_i2c);
4447*4882a593Smuzhiyun 	clk_disable_unprepare(it6616->xvclk);
4448*4882a593Smuzhiyun 
4449*4882a593Smuzhiyun 	return 0;
4450*4882a593Smuzhiyun }
4451*4882a593Smuzhiyun 
4452*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF)
4453*4882a593Smuzhiyun static const struct of_device_id it6616_of_match[] = {
4454*4882a593Smuzhiyun 	{ .compatible = "ite,it6616" },
4455*4882a593Smuzhiyun 	{},
4456*4882a593Smuzhiyun };
4457*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, it6616_of_match);
4458*4882a593Smuzhiyun #endif
4459*4882a593Smuzhiyun 
4460*4882a593Smuzhiyun static struct i2c_driver it6616_driver = {
4461*4882a593Smuzhiyun 	.driver = {
4462*4882a593Smuzhiyun 		.name = IT6616_NAME,
4463*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(it6616_of_match),
4464*4882a593Smuzhiyun 	},
4465*4882a593Smuzhiyun 	.probe = it6616_probe,
4466*4882a593Smuzhiyun 	.remove = it6616_remove,
4467*4882a593Smuzhiyun };
4468*4882a593Smuzhiyun 
it6616_driver_init(void)4469*4882a593Smuzhiyun static int __init it6616_driver_init(void)
4470*4882a593Smuzhiyun {
4471*4882a593Smuzhiyun 	return i2c_add_driver(&it6616_driver);
4472*4882a593Smuzhiyun }
4473*4882a593Smuzhiyun 
it6616_driver_exit(void)4474*4882a593Smuzhiyun static void __exit it6616_driver_exit(void)
4475*4882a593Smuzhiyun {
4476*4882a593Smuzhiyun 	i2c_del_driver(&it6616_driver);
4477*4882a593Smuzhiyun }
4478*4882a593Smuzhiyun 
4479*4882a593Smuzhiyun device_initcall_sync(it6616_driver_init);
4480*4882a593Smuzhiyun module_exit(it6616_driver_exit);
4481*4882a593Smuzhiyun 
4482*4882a593Smuzhiyun MODULE_DESCRIPTION("ITE it6616 HDMI to CSI-2 bridge driver");
4483*4882a593Smuzhiyun MODULE_AUTHOR("Jianwei Fan <jianwei.fan@rock-chips.com>");
4484*4882a593Smuzhiyun MODULE_AUTHOR("Kenneth Hung<Kenneth.Hung@ite.com.tw>");
4485*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4486