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, ®_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