xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/vehicle/vehicle_ad_7181.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * vehicle sensor adv7181
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2022 Rockchip Electronics Co.Ltd
6*4882a593Smuzhiyun  * Authors:
7*4882a593Smuzhiyun  *      Zhiqin Wei <wzq@rock-chips.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/sched.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <linux/sysctl.h>
18*4882a593Smuzhiyun #include <linux/interrupt.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/proc_fs.h>
21*4882a593Smuzhiyun #include <linux/suspend.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/io.h>
24*4882a593Smuzhiyun #include <linux/irq.h>
25*4882a593Smuzhiyun #include <linux/uaccess.h>
26*4882a593Smuzhiyun #include <linux/of_gpio.h>
27*4882a593Smuzhiyun #include <linux/of_irq.h>
28*4882a593Smuzhiyun #include <linux/videodev2.h>
29*4882a593Smuzhiyun #include "vehicle_cfg.h"
30*4882a593Smuzhiyun #include "vehicle_main.h"
31*4882a593Smuzhiyun #include "vehicle_ad.h"
32*4882a593Smuzhiyun #include "vehicle_ad_7181.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun enum {
35*4882a593Smuzhiyun 	FORCE_PAL_WIDTH = 720,
36*4882a593Smuzhiyun 	FORCE_PAL_HEIGHT = 576,
37*4882a593Smuzhiyun 	FORCE_NTSC_WIDTH = 720,
38*4882a593Smuzhiyun 	FORCE_NTSC_HEIGHT = 480,
39*4882a593Smuzhiyun 	FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static struct vehicle_ad_dev *ad7181_g_addev;
43*4882a593Smuzhiyun static v4l2_std_id std_old = V4L2_STD_NTSC;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define SENSOR_REGISTER_LEN	1	/* sensor register address bytes*/
46*4882a593Smuzhiyun #define SENSOR_VALUE_LEN	1	/* sensor register value bytes*/
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun struct rk_sensor_reg {
49*4882a593Smuzhiyun 	unsigned int reg;
50*4882a593Smuzhiyun 	unsigned int val;
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define ADV7181_STATUS1_REG		0x10
54*4882a593Smuzhiyun #define ADV7181_STATUS1_IN_LOCK		0x01
55*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_MASK	0x70
56*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_NTSM_M_J	0x00
57*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_NTSC_4_43 0x10
58*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_PAL_M	0x20
59*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_PAL_60	0x30
60*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_PAL_B_G	0x40
61*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_SECAM	0x50
62*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_PAL_COMB	0x60
63*4882a593Smuzhiyun #define ADV7181_STATUS1_AUTOD_SECAM_525	0x70
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define ADV7181_INPUT_CONTROL		0x00
66*4882a593Smuzhiyun #define ADV7181_INPUT_DEFAULT		0x00
67*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN2		0x00
68*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN3		0x01
69*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN5		0x02
70*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN6		0x03
71*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN8		0x04
72*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN10	0x05
73*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN1		0x0B
74*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN4		0x0D
75*4882a593Smuzhiyun #define ADV7181_INPUT_CVBS_AIN7		0x0F
76*4882a593Smuzhiyun #define ADV7181_INPUT_YPRPB_AIN6_8_10	0x00
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #define SEQCMD_END  0xFF000000
79*4882a593Smuzhiyun #define SensorEnd   {SEQCMD_END, 0x00}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define SENSOR_DG VEHICLE_DG
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /* Preview resolution setting*/
84*4882a593Smuzhiyun static struct rk_sensor_reg sensor_preview_data[] = {
85*4882a593Smuzhiyun 	/* autodetect cvbs in ntsc/pal/secam 8-bit 422 encode */
86*4882a593Smuzhiyun 	{0x00, 0x0B}, /*cvbs in AIN1*/
87*4882a593Smuzhiyun 	{0x04, 0x77},
88*4882a593Smuzhiyun 	{0x17, 0x41},
89*4882a593Smuzhiyun 	{0x1D, 0x47},
90*4882a593Smuzhiyun 	{0x31, 0x02},
91*4882a593Smuzhiyun 	{0x3A, 0x17},
92*4882a593Smuzhiyun 	{0x3B, 0x81},
93*4882a593Smuzhiyun 	{0x3D, 0xA2},
94*4882a593Smuzhiyun 	{0x3E, 0x6A},
95*4882a593Smuzhiyun 	{0x3F, 0xA0},
96*4882a593Smuzhiyun 	{0x86, 0x0B},
97*4882a593Smuzhiyun 	{0xF3, 0x01},
98*4882a593Smuzhiyun 	{0xF9, 0x03},
99*4882a593Smuzhiyun 	{0x0E, 0x80},
100*4882a593Smuzhiyun 	{0x52, 0x46},
101*4882a593Smuzhiyun 	{0x54, 0x80},
102*4882a593Smuzhiyun 	{0x7F, 0xFF},
103*4882a593Smuzhiyun 	{0x81, 0x30},
104*4882a593Smuzhiyun 	{0x90, 0xC9},
105*4882a593Smuzhiyun 	{0x91, 0x40},
106*4882a593Smuzhiyun 	{0x92, 0x3C},
107*4882a593Smuzhiyun 	{0x93, 0xCA},
108*4882a593Smuzhiyun 	{0x94, 0xD5},
109*4882a593Smuzhiyun 	{0xB1, 0xFF},
110*4882a593Smuzhiyun 	{0xB6, 0x08},
111*4882a593Smuzhiyun 	{0xC0, 0x9A},
112*4882a593Smuzhiyun 	{0xCF, 0x50},
113*4882a593Smuzhiyun 	{0xD0, 0x4E},
114*4882a593Smuzhiyun 	{0xD1, 0xB9},
115*4882a593Smuzhiyun 	{0xD6, 0xDD},
116*4882a593Smuzhiyun 	{0xD7, 0xE2},
117*4882a593Smuzhiyun 	{0xE5, 0x51},
118*4882a593Smuzhiyun 	{0xF6, 0x3B},
119*4882a593Smuzhiyun 	{0x0E, 0x00},
120*4882a593Smuzhiyun 	{0x03, 0x4C}, //stream off
121*4882a593Smuzhiyun 	{0xDF, 0X46},
122*4882a593Smuzhiyun 	{0xC9, 0x04},
123*4882a593Smuzhiyun 	{0xC5, 0x81},
124*4882a593Smuzhiyun 	{0xC4, 0x34},
125*4882a593Smuzhiyun 	{0xBf, 0x02},
126*4882a593Smuzhiyun 	{0xB5, 0x83},
127*4882a593Smuzhiyun 	{0xB6, 0x00},
128*4882a593Smuzhiyun 	{0xaf, 0x03},
129*4882a593Smuzhiyun 	{0xae, 0x00},
130*4882a593Smuzhiyun 	{0xac, 0x00},
131*4882a593Smuzhiyun 	{0xAB, 0x00},
132*4882a593Smuzhiyun 	{0xa1, 0xFF},
133*4882a593Smuzhiyun 	{0xA2, 0x00},
134*4882a593Smuzhiyun 	{0xA3, 0x00},
135*4882a593Smuzhiyun 	{0xA4, 0x00},
136*4882a593Smuzhiyun 	{0xa5, 0x01},
137*4882a593Smuzhiyun 	{0xA6, 0x00},
138*4882a593Smuzhiyun 	{0xA6, 0x00},
139*4882a593Smuzhiyun 	{0xA7, 0x00},
140*4882a593Smuzhiyun 	{0xA8, 0x00},
141*4882a593Smuzhiyun 	{0xa0, 0x03},
142*4882a593Smuzhiyun 	{0x98, 0X00},
143*4882a593Smuzhiyun 	{0x97, 0X00},
144*4882a593Smuzhiyun 	{0X90, 0X00},
145*4882a593Smuzhiyun 	{0X85, 0X02},
146*4882a593Smuzhiyun 	{0x7B, 0x1E},
147*4882a593Smuzhiyun 	{0x74, 0x04},
148*4882a593Smuzhiyun 	{0x75, 0x01},
149*4882a593Smuzhiyun 	{0x76, 0x00},
150*4882a593Smuzhiyun 	{0x6B, 0xC0},
151*4882a593Smuzhiyun 	{0x67, 0x03},
152*4882a593Smuzhiyun 	{0x3C, 0x58},
153*4882a593Smuzhiyun 	{0x30, 0x4C},
154*4882a593Smuzhiyun 	{0x2E, 0X9F},
155*4882a593Smuzhiyun 	{0x12, 0XC0},
156*4882a593Smuzhiyun 	{0x10, 0X0D},
157*4882a593Smuzhiyun 	{0x05, 0X00},
158*4882a593Smuzhiyun 	{0x06, 0X02},
159*4882a593Smuzhiyun 	{0x60, 0x01},
160*4882a593Smuzhiyun 	SensorEnd
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static struct rk_sensor_reg sensor_preview_data_yprpb_p[] = {
164*4882a593Smuzhiyun 	{0x05, 0x01},
165*4882a593Smuzhiyun 	{0x06, 0x06},
166*4882a593Smuzhiyun 	{0xc3, 0x56},
167*4882a593Smuzhiyun 	{0xc4, 0xb4},
168*4882a593Smuzhiyun 	{0x1d, 0x47},
169*4882a593Smuzhiyun 	{0x3a, 0x11},
170*4882a593Smuzhiyun 	{0x3b, 0x81},
171*4882a593Smuzhiyun 	{0x3c, 0x3b},
172*4882a593Smuzhiyun 	{0x6b, 0x83},
173*4882a593Smuzhiyun 	{0xc9, 0x00},
174*4882a593Smuzhiyun 	{0x73, 0x10},
175*4882a593Smuzhiyun 	{0x74, 0xa3},
176*4882a593Smuzhiyun 	{0x75, 0xe8},
177*4882a593Smuzhiyun 	{0x76, 0xfa},
178*4882a593Smuzhiyun 	{0x7b, 0x1c},
179*4882a593Smuzhiyun 	{0x85, 0x19},
180*4882a593Smuzhiyun 	{0x86, 0x0b},
181*4882a593Smuzhiyun 	{0xbf, 0x06},
182*4882a593Smuzhiyun 	{0xc0, 0x40},
183*4882a593Smuzhiyun 	{0xc1, 0xf0},
184*4882a593Smuzhiyun 	{0xc2, 0x80},
185*4882a593Smuzhiyun 	{0xc5, 0x01},
186*4882a593Smuzhiyun 	{0xc9, 0x08},
187*4882a593Smuzhiyun 	{0x0e, 0x80},
188*4882a593Smuzhiyun 	{0x52, 0x46},
189*4882a593Smuzhiyun 	{0x54, 0x80},
190*4882a593Smuzhiyun 	{0x57, 0x01},
191*4882a593Smuzhiyun 	{0xf6, 0x3b},
192*4882a593Smuzhiyun 	{0x0e, 0x00},
193*4882a593Smuzhiyun 	{0x67, 0x2f},
194*4882a593Smuzhiyun 	{0x03, 0x4C}, //disable out put
195*4882a593Smuzhiyun 	SensorEnd
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun 
adv7181_std_to_v4l2(u8 status1)198*4882a593Smuzhiyun static v4l2_std_id adv7181_std_to_v4l2(u8 status1)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	/* in case V4L2_IN_ST_NO_SIGNAL */
201*4882a593Smuzhiyun 	if (!(status1 & ADV7181_STATUS1_IN_LOCK))
202*4882a593Smuzhiyun 		return V4L2_STD_UNKNOWN;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	switch (status1 & ADV7181_STATUS1_AUTOD_MASK) {
205*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_PAL_M:
206*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_NTSM_M_J:
207*4882a593Smuzhiyun 		return V4L2_STD_NTSC;
208*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_NTSC_4_43:
209*4882a593Smuzhiyun 		return V4L2_STD_NTSC_443;
210*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_PAL_60:
211*4882a593Smuzhiyun 		return V4L2_STD_PAL_60;
212*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_PAL_B_G:
213*4882a593Smuzhiyun 		return V4L2_STD_PAL;
214*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_SECAM:
215*4882a593Smuzhiyun 		return V4L2_STD_SECAM;
216*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_PAL_COMB:
217*4882a593Smuzhiyun 		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
218*4882a593Smuzhiyun 	case ADV7181_STATUS1_AUTOD_SECAM_525:
219*4882a593Smuzhiyun 		return V4L2_STD_SECAM;
220*4882a593Smuzhiyun 	default:
221*4882a593Smuzhiyun 		return V4L2_STD_UNKNOWN;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
adv7181_status_to_v4l2(u8 status1)225*4882a593Smuzhiyun static u32 adv7181_status_to_v4l2(u8 status1)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	if (!(status1 & ADV7181_STATUS1_IN_LOCK))
228*4882a593Smuzhiyun 		return V4L2_IN_ST_NO_SIGNAL;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	return 0;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
adv7181_vehicle_status(struct vehicle_ad_dev * ad,u32 * status,v4l2_std_id * std)233*4882a593Smuzhiyun static int adv7181_vehicle_status(struct vehicle_ad_dev *ad,
234*4882a593Smuzhiyun 				  u32 *status,
235*4882a593Smuzhiyun 				  v4l2_std_id *std)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	unsigned char status1 = 0;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	status1 = vehicle_generic_sensor_read(ad, ADV7181_STATUS1_REG);
240*4882a593Smuzhiyun 	if (status1)
241*4882a593Smuzhiyun 		return status1;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (status)
244*4882a593Smuzhiyun 		*status = adv7181_status_to_v4l2(status1);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (std)
247*4882a593Smuzhiyun 		*std = adv7181_std_to_v4l2(status1);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return 0;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
adv7181_reinit_parameter(struct vehicle_ad_dev * ad,v4l2_std_id std)252*4882a593Smuzhiyun static void adv7181_reinit_parameter(struct vehicle_ad_dev *ad, v4l2_std_id std)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	int i;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (ad7181_g_addev->ad_chl == 0) {
257*4882a593Smuzhiyun 		ad->cfg.width = 1024;
258*4882a593Smuzhiyun 		ad->cfg.height = 500;
259*4882a593Smuzhiyun 		ad->cfg.start_x = 56;
260*4882a593Smuzhiyun 		ad->cfg.start_y = 0;
261*4882a593Smuzhiyun 		ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
262*4882a593Smuzhiyun 		ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
263*4882a593Smuzhiyun 		ad->cfg.field_order = 0;
264*4882a593Smuzhiyun 		ad->cfg.yuv_order = 1;
265*4882a593Smuzhiyun 		ad->cfg.href = 0;
266*4882a593Smuzhiyun 		ad->cfg.vsync = 0;
267*4882a593Smuzhiyun 		ad->cfg.frame_rate = 60;
268*4882a593Smuzhiyun 		ad->cfg.type = V4L2_MBUS_PARALLEL;
269*4882a593Smuzhiyun 		ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
270*4882a593Smuzhiyun 					V4L2_MBUS_VSYNC_ACTIVE_LOW |
271*4882a593Smuzhiyun 					V4L2_MBUS_PCLK_SAMPLE_RISING;
272*4882a593Smuzhiyun 	} else if (std == V4L2_STD_PAL) {
273*4882a593Smuzhiyun 		ad->cfg.width = FORCE_PAL_WIDTH;
274*4882a593Smuzhiyun 		ad->cfg.height = FORCE_PAL_HEIGHT;
275*4882a593Smuzhiyun 		ad->cfg.start_x = 0;
276*4882a593Smuzhiyun 		ad->cfg.start_y = 0;
277*4882a593Smuzhiyun 		ad->cfg.input_format = CIF_INPUT_FORMAT_PAL;
278*4882a593Smuzhiyun 		ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
279*4882a593Smuzhiyun 		ad->cfg.field_order = 0;
280*4882a593Smuzhiyun 		ad->cfg.yuv_order = 0;
281*4882a593Smuzhiyun 		ad->cfg.href = 0;
282*4882a593Smuzhiyun 		ad->cfg.vsync = 0;
283*4882a593Smuzhiyun 		ad->cfg.frame_rate = 25;
284*4882a593Smuzhiyun 		ad->cfg.type = V4L2_MBUS_PARALLEL;
285*4882a593Smuzhiyun 		ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
286*4882a593Smuzhiyun 					V4L2_MBUS_VSYNC_ACTIVE_LOW |
287*4882a593Smuzhiyun 					V4L2_MBUS_PCLK_SAMPLE_RISING;
288*4882a593Smuzhiyun 	} else {
289*4882a593Smuzhiyun 		ad->cfg.width = FORCE_NTSC_WIDTH;
290*4882a593Smuzhiyun 		ad->cfg.height = FORCE_NTSC_HEIGHT;
291*4882a593Smuzhiyun 		ad->cfg.start_x = 0;
292*4882a593Smuzhiyun 		ad->cfg.start_y = 0;
293*4882a593Smuzhiyun 		ad->cfg.input_format = CIF_INPUT_FORMAT_NTSC;
294*4882a593Smuzhiyun 		ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
295*4882a593Smuzhiyun 		ad->cfg.field_order = 0;
296*4882a593Smuzhiyun 		ad->cfg.yuv_order = 2;
297*4882a593Smuzhiyun 		ad->cfg.href = 0;
298*4882a593Smuzhiyun 		ad->cfg.vsync = 0;
299*4882a593Smuzhiyun 		ad->cfg.frame_rate = 30;
300*4882a593Smuzhiyun 		ad->cfg.type = V4L2_MBUS_PARALLEL;
301*4882a593Smuzhiyun 		ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
302*4882a593Smuzhiyun 					V4L2_MBUS_VSYNC_ACTIVE_LOW |
303*4882a593Smuzhiyun 					V4L2_MBUS_PCLK_SAMPLE_RISING;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* fix crop info from dts config */
307*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
308*4882a593Smuzhiyun 		if ((ad->defrects[i].width == ad->cfg.width) &&
309*4882a593Smuzhiyun 		    (ad->defrects[i].height == ad->cfg.height)) {
310*4882a593Smuzhiyun 			ad->cfg.start_x = ad->defrects[i].crop_x;
311*4882a593Smuzhiyun 			ad->cfg.start_y = ad->defrects[i].crop_y;
312*4882a593Smuzhiyun 			ad->cfg.width = ad->defrects[i].crop_width;
313*4882a593Smuzhiyun 			ad->cfg.height = ad->defrects[i].crop_height;
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	SENSOR_DG("size %dx%d, crop(%d,%d)\n",
318*4882a593Smuzhiyun 	    ad->cfg.width, ad->cfg.height,
319*4882a593Smuzhiyun 	    ad->cfg.start_x, ad->cfg.start_y);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
adv7181_reg_init(struct vehicle_ad_dev * ad,unsigned char cvstd)322*4882a593Smuzhiyun static void adv7181_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct rk_sensor_reg *sensor;
325*4882a593Smuzhiyun 	int i = 0;
326*4882a593Smuzhiyun 	unsigned char val[2];
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	switch (ad->ad_chl) {
329*4882a593Smuzhiyun 	case 0:
330*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
331*4882a593Smuzhiyun 		break;
332*4882a593Smuzhiyun 	case 1:
333*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_CVBS_AIN6;
334*4882a593Smuzhiyun 		break;
335*4882a593Smuzhiyun 	case 2:
336*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_CVBS_AIN8;
337*4882a593Smuzhiyun 		break;
338*4882a593Smuzhiyun 	case 3:
339*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_CVBS_AIN10;
340*4882a593Smuzhiyun 		break;
341*4882a593Smuzhiyun 	case 4:
342*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_YPRPB_AIN6_8_10;
343*4882a593Smuzhiyun 		break;
344*4882a593Smuzhiyun 	default:
345*4882a593Smuzhiyun 		ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 	val[0] = ad->ad_chl;
348*4882a593Smuzhiyun 	vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (ad->ad_chl == ADV7181_INPUT_YPRPB_AIN6_8_10) {
351*4882a593Smuzhiyun 		SENSOR_DG("%s %d set sensor_preview_data_yprpb_p/p", __func__, __LINE__);
352*4882a593Smuzhiyun 		sensor = sensor_preview_data_yprpb_p;
353*4882a593Smuzhiyun 	} else {
354*4882a593Smuzhiyun 		SENSOR_DG("%s %d set n/p", __func__, __LINE__);
355*4882a593Smuzhiyun 		sensor = sensor_preview_data;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 	while ((sensor[i].reg != SEQCMD_END) && (sensor[i].reg != 0xFC000000)) {
358*4882a593Smuzhiyun 		if (sensor[i].reg == ADV7181_INPUT_CONTROL) {
359*4882a593Smuzhiyun 			SENSOR_DG("%s %d lkg test ad channel = %d\n",
360*4882a593Smuzhiyun 					__func__, __LINE__, ad->ad_chl);
361*4882a593Smuzhiyun 		} else {
362*4882a593Smuzhiyun 			val[0] = sensor[i].val;
363*4882a593Smuzhiyun 			vehicle_generic_sensor_write(ad, sensor[i].reg, val);
364*4882a593Smuzhiyun 		}
365*4882a593Smuzhiyun 		i++;
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	val[0] = ad->ad_chl;
369*4882a593Smuzhiyun 	vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
adv7181_ad_get_cfg(struct vehicle_cfg ** cfg)372*4882a593Smuzhiyun int adv7181_ad_get_cfg(struct vehicle_cfg **cfg)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	u32 status;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (!ad7181_g_addev)
377*4882a593Smuzhiyun 		return -1;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	adv7181_vehicle_status(ad7181_g_addev, &status, NULL);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	ad7181_g_addev->cfg.ad_ready = true;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	*cfg = &ad7181_g_addev->cfg;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return 0;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
adv7181_ad_check_cif_error(struct vehicle_ad_dev * ad,int last_line)388*4882a593Smuzhiyun void adv7181_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	SENSOR_DG("%s, last_line %d\n", __func__, last_line);
391*4882a593Smuzhiyun 	if (last_line < 1)
392*4882a593Smuzhiyun 		return;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	ad->cif_error_last_line = last_line;
395*4882a593Smuzhiyun 	if (std_old == V4L2_STD_PAL) {
396*4882a593Smuzhiyun 		if (last_line == FORCE_NTSC_HEIGHT) {
397*4882a593Smuzhiyun 			if (ad->state_check_work.state_check_wq)
398*4882a593Smuzhiyun 				queue_delayed_work(
399*4882a593Smuzhiyun 					ad->state_check_work.state_check_wq,
400*4882a593Smuzhiyun 					&ad->state_check_work.work,
401*4882a593Smuzhiyun 					msecs_to_jiffies(0));
402*4882a593Smuzhiyun 		}
403*4882a593Smuzhiyun 	} else if (std_old == V4L2_STD_NTSC) {
404*4882a593Smuzhiyun 		if (last_line == FORCE_PAL_HEIGHT) {
405*4882a593Smuzhiyun 			if (ad->state_check_work.state_check_wq)
406*4882a593Smuzhiyun 				queue_delayed_work(
407*4882a593Smuzhiyun 					ad->state_check_work.state_check_wq,
408*4882a593Smuzhiyun 					&ad->state_check_work.work,
409*4882a593Smuzhiyun 					msecs_to_jiffies(0));
410*4882a593Smuzhiyun 		}
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
adv7181_check_id(struct vehicle_ad_dev * ad)414*4882a593Smuzhiyun int adv7181_check_id(struct vehicle_ad_dev *ad)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	int ret = 0;
417*4882a593Smuzhiyun 	int val;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	val = vehicle_generic_sensor_read(ad, 0x11);
420*4882a593Smuzhiyun 	SENSOR_DG("%s vehicle read 0x11 --> 0x%02x\n", ad->ad_name, val);
421*4882a593Smuzhiyun 	if (val != 0x20) {
422*4882a593Smuzhiyun 		SENSOR_DG("%s vehicle wrong camera ID, expected 0x20, detected 0x%02x\n",
423*4882a593Smuzhiyun 		    ad->ad_name, val);
424*4882a593Smuzhiyun 		ret = -EINVAL;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	return ret;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
adv7181_check_std(struct vehicle_ad_dev * ad,v4l2_std_id * std)430*4882a593Smuzhiyun static int adv7181_check_std(struct vehicle_ad_dev *ad, v4l2_std_id *std)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 	u32 status = 0;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	adv7181_vehicle_status(ad, &status, std);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	if (status != 0) { /* No signal */
437*4882a593Smuzhiyun 		mdelay(30);
438*4882a593Smuzhiyun 		adv7181_vehicle_status(ad, &status, std);
439*4882a593Smuzhiyun 		SENSOR_DG("status 0x%x\n", status);
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	return 0;
443*4882a593Smuzhiyun }
adv7181_channel_set(struct vehicle_ad_dev * ad,int channel)444*4882a593Smuzhiyun void adv7181_channel_set(struct vehicle_ad_dev *ad, int channel)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	static int channel_change = 11;
447*4882a593Smuzhiyun 	v4l2_std_id std = 0;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	ad->ad_chl = channel;
450*4882a593Smuzhiyun 	adv7181_reg_init(ad, std);
451*4882a593Smuzhiyun 	adv7181_check_std(ad, &std);
452*4882a593Smuzhiyun 	adv7181_reinit_parameter(ad, std);
453*4882a593Smuzhiyun 	if (channel_change != ad->ad_chl) {
454*4882a593Smuzhiyun 		SENSOR_DG("%s %d channel changed now channel = %d old_channel = %d\n",
455*4882a593Smuzhiyun 						__func__, __LINE__, ad->ad_chl, channel);
456*4882a593Smuzhiyun 		channel_change = ad->ad_chl;
457*4882a593Smuzhiyun 		vehicle_ad_stat_change_notify();
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
adv7181_stream(struct vehicle_ad_dev * ad,int value)461*4882a593Smuzhiyun int adv7181_stream(struct vehicle_ad_dev *ad, int value)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	char val;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	if (value)
466*4882a593Smuzhiyun 		val = 0x0c;	//on
467*4882a593Smuzhiyun 	else
468*4882a593Smuzhiyun 		val = 0x4c;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	SENSOR_DG("stream write 0x%x to reg 0x03\n", val);
471*4882a593Smuzhiyun 	vehicle_generic_sensor_write(ad, 0x03, &val);
472*4882a593Smuzhiyun 	if (value)
473*4882a593Smuzhiyun 		val = 0x47;	//on
474*4882a593Smuzhiyun 	else
475*4882a593Smuzhiyun 		val = 0x87;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	SENSOR_DG("stream write 0x%x to reg 0x01d\n", val);
478*4882a593Smuzhiyun 	vehicle_generic_sensor_write(ad, 0x1d, &val);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
power_on(struct vehicle_ad_dev * ad)483*4882a593Smuzhiyun static void power_on(struct vehicle_ad_dev *ad)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	/* gpio_direction_output(ad->power, ad->pwr_active); */
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if (gpio_is_valid(ad->powerdown)) {
488*4882a593Smuzhiyun 		gpio_request(ad->powerdown, "ad_powerdown");
489*4882a593Smuzhiyun 		gpio_direction_output(ad->powerdown, !ad->pwdn_active);
490*4882a593Smuzhiyun 		/* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	if (gpio_is_valid(ad->power)) {
494*4882a593Smuzhiyun 		gpio_request(ad->power, "ad_power");
495*4882a593Smuzhiyun 		gpio_direction_output(ad->power, ad->pwr_active);
496*4882a593Smuzhiyun 		/* gpio_set_value(ad->power, ad->pwr_active); */
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if (gpio_is_valid(ad->reset)) {
500*4882a593Smuzhiyun 		gpio_request(ad->reset, "ad_reset");
501*4882a593Smuzhiyun 		gpio_direction_output(ad->reset, 0);
502*4882a593Smuzhiyun 		usleep_range(10000, 12000);
503*4882a593Smuzhiyun 		gpio_set_value(ad->reset, 1);
504*4882a593Smuzhiyun 		usleep_range(10000, 12000);
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
power_off(struct vehicle_ad_dev * ad)508*4882a593Smuzhiyun static void power_off(struct vehicle_ad_dev *ad)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	if (gpio_is_valid(ad->powerdown))
511*4882a593Smuzhiyun 		gpio_free(ad->powerdown);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	if (gpio_is_valid(ad->power))
514*4882a593Smuzhiyun 		gpio_free(ad->power);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (gpio_is_valid(ad->reset))
517*4882a593Smuzhiyun 		gpio_free(ad->reset);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
adv7181_check_state_work(struct work_struct * work)520*4882a593Smuzhiyun static void adv7181_check_state_work(struct work_struct *work)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct vehicle_ad_dev *ad;
523*4882a593Smuzhiyun 	v4l2_std_id std;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	ad = ad7181_g_addev;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	if (ad->cif_error_last_line > 0)
528*4882a593Smuzhiyun 		ad->cif_error_last_line = 0;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	adv7181_check_std(ad, &std);
531*4882a593Smuzhiyun 	SENSOR_DG("%s:new std(%llx), std_old(%llx)\n", __func__, std, std_old);
532*4882a593Smuzhiyun 	if (std != std_old) {
533*4882a593Smuzhiyun 		std_old = std;
534*4882a593Smuzhiyun 		adv7181_reinit_parameter(ad, std);
535*4882a593Smuzhiyun 		SENSOR_DG("%s:ad signal change notify\n", __func__);
536*4882a593Smuzhiyun 		vehicle_ad_stat_change_notify();
537*4882a593Smuzhiyun 	}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	queue_delayed_work(ad->state_check_work.state_check_wq,
540*4882a593Smuzhiyun 			   &ad->state_check_work.work, msecs_to_jiffies(3000));
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
adv7181_ad_deinit(void)543*4882a593Smuzhiyun int adv7181_ad_deinit(void)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	struct vehicle_ad_dev *ad;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	ad = ad7181_g_addev;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (!ad)
550*4882a593Smuzhiyun 		return -ENODEV;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	if (ad->state_check_work.state_check_wq) {
553*4882a593Smuzhiyun 		cancel_delayed_work_sync(&ad->state_check_work.work);
554*4882a593Smuzhiyun 		flush_delayed_work(&ad->state_check_work.work);
555*4882a593Smuzhiyun 		flush_workqueue(ad->state_check_work.state_check_wq);
556*4882a593Smuzhiyun 		destroy_workqueue(ad->state_check_work.state_check_wq);
557*4882a593Smuzhiyun 	}
558*4882a593Smuzhiyun 	if (ad->irq)
559*4882a593Smuzhiyun 		free_irq(ad->irq, ad);
560*4882a593Smuzhiyun 	power_off(ad);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
adv7181_ad_init(struct vehicle_ad_dev * ad)565*4882a593Smuzhiyun int adv7181_ad_init(struct vehicle_ad_dev *ad)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	v4l2_std_id std = V4L2_STD_NTSC;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	if (!ad)
570*4882a593Smuzhiyun 		return -1;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	ad7181_g_addev = ad;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/*  1. i2c init */
575*4882a593Smuzhiyun 	while (ad->adapter == NULL) {
576*4882a593Smuzhiyun 		ad->adapter = i2c_get_adapter(ad->i2c_chl);
577*4882a593Smuzhiyun 		usleep_range(10000, 12000);
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
581*4882a593Smuzhiyun 		return -EIO;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	/*  2. ad power on sequence */
584*4882a593Smuzhiyun 	power_on(ad);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	/* fix mode */
587*4882a593Smuzhiyun 	adv7181_check_std(ad, &std);
588*4882a593Smuzhiyun 	std_old = std;
589*4882a593Smuzhiyun 	SENSOR_DG("std: %s\n", (std == V4L2_STD_NTSC) ? "ntsc" : "pal");
590*4882a593Smuzhiyun 	SENSOR_DG("std_old: %s\n", (std_old == V4L2_STD_NTSC) ? "ntsc" : "pal");
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	/*  3 .init default format params */
593*4882a593Smuzhiyun 	adv7181_reg_init(ad, std);
594*4882a593Smuzhiyun 	adv7181_reinit_parameter(ad, std);
595*4882a593Smuzhiyun 	vehicle_ad_stat_change_notify();
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/*  5. create workqueue to detect signal change */
598*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&ad->state_check_work.work, adv7181_check_state_work);
599*4882a593Smuzhiyun 	ad->state_check_work.state_check_wq =
600*4882a593Smuzhiyun 		create_singlethread_workqueue("vehicle-ad-adv7181");
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	queue_delayed_work(ad->state_check_work.state_check_wq,
603*4882a593Smuzhiyun 			   &ad->state_check_work.work, msecs_to_jiffies(100));
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	return 0;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 
609