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