1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * vehicle sensor max96714
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
6*4882a593Smuzhiyun * Authors:
7*4882a593Smuzhiyun * Jianwei Fan <jianwei.fan@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 "vehicle_cfg.h"
29*4882a593Smuzhiyun #include "vehicle_main.h"
30*4882a593Smuzhiyun #include "vehicle_ad.h"
31*4882a593Smuzhiyun #include "vehicle_ad_max96714.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun enum {
34*4882a593Smuzhiyun CVSTD_720P60 = 0,
35*4882a593Smuzhiyun CVSTD_720P50,
36*4882a593Smuzhiyun CVSTD_1080P30,
37*4882a593Smuzhiyun CVSTD_1080P25,
38*4882a593Smuzhiyun CVSTD_720P30,
39*4882a593Smuzhiyun CVSTD_720P25,
40*4882a593Smuzhiyun CVSTD_SVGAP30,
41*4882a593Smuzhiyun CVSTD_SD,
42*4882a593Smuzhiyun CVSTD_NTSC,
43*4882a593Smuzhiyun CVSTD_PAL
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun enum {
47*4882a593Smuzhiyun FORCE_PAL_WIDTH = 960,
48*4882a593Smuzhiyun FORCE_PAL_HEIGHT = 576,
49*4882a593Smuzhiyun FORCE_NTSC_WIDTH = 960,
50*4882a593Smuzhiyun FORCE_NTSC_HEIGHT = 480,
51*4882a593Smuzhiyun FORCE_SVGA_WIDTH = 800,
52*4882a593Smuzhiyun FORCE_SVGA_HEIGHT = 600,
53*4882a593Smuzhiyun FORCE_720P_WIDTH = 1280,
54*4882a593Smuzhiyun FORCE_720P_HEIGHT = 720,
55*4882a593Smuzhiyun FORCE_1080P_WIDTH = 1920,
56*4882a593Smuzhiyun FORCE_1080P_HEIGHT = 1080,
57*4882a593Smuzhiyun FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun enum {
61*4882a593Smuzhiyun VIDEO_UNPLUG,
62*4882a593Smuzhiyun VIDEO_IN,
63*4882a593Smuzhiyun VIDEO_LOCKED,
64*4882a593Smuzhiyun VIDEO_UNLOCK
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #define FLAG_LOCKED (0x1 << 3)
68*4882a593Smuzhiyun #define MAX96714_LINK_FREQ_150M 150000000UL
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static struct vehicle_ad_dev *max96714_g_addev;
71*4882a593Smuzhiyun static int cvstd_mode = CVSTD_1080P30;
72*4882a593Smuzhiyun //static int cvstd_old = CVSTD_720P25;
73*4882a593Smuzhiyun static int cvstd_old = CVSTD_NTSC;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun //static int cvstd_sd = CVSTD_NTSC;
76*4882a593Smuzhiyun static int cvstd_state = VIDEO_UNPLUG;
77*4882a593Smuzhiyun static int cvstd_old_state = VIDEO_UNLOCK;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static bool g_max96714_streaming;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #define SENSOR_VALUE_LEN 1 /* sensor register value bytes*/
82*4882a593Smuzhiyun #define MAX96714_CHIP_ID 0xC9
83*4882a593Smuzhiyun #define MAX96714_CHIP_ID_REG 0x0D
84*4882a593Smuzhiyun #define MAX96714_GMSL_STATE 0x0013
85*4882a593Smuzhiyun #define MAX96714_STREAM_CTL 0x0313
86*4882a593Smuzhiyun #define MAX96714_MODE_SW_STANDBY 0x0
87*4882a593Smuzhiyun #define MAX96714_MODE_STREAMING BIT(1)
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun struct regval {
90*4882a593Smuzhiyun u16 reg;
91*4882a593Smuzhiyun u8 val;
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun #define REG_NULL 0xFFFF
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* 1080p Preview resolution setting*/
96*4882a593Smuzhiyun static struct regval sensor_preview_data_1080p_30hz[] = {
97*4882a593Smuzhiyun {0x0313, 0x00},
98*4882a593Smuzhiyun {0x0001, 0x01},
99*4882a593Smuzhiyun {0x0010, 0x21},
100*4882a593Smuzhiyun {0x0320, 0x23},
101*4882a593Smuzhiyun {0x0325, 0x80},
102*4882a593Smuzhiyun {0x0313, 0x00},
103*4882a593Smuzhiyun {REG_NULL, 0x00},
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun static struct rkmodule_csi_dphy_param max96714_dcphy_param = {
107*4882a593Smuzhiyun .vendor = PHY_VENDOR_SAMSUNG,
108*4882a593Smuzhiyun .lp_vol_ref = 3,
109*4882a593Smuzhiyun .lp_hys_sw = {3, 0, 0, 0},
110*4882a593Smuzhiyun .lp_escclk_pol_sel = {1, 0, 0, 0},
111*4882a593Smuzhiyun .skew_data_cal_clk = {0, 3, 3, 3},
112*4882a593Smuzhiyun .clk_hs_term_sel = 2,
113*4882a593Smuzhiyun .data_hs_term_sel = {2, 2, 2, 2},
114*4882a593Smuzhiyun .reserved = {0},
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun
max96714_read_reg(struct vehicle_ad_dev * ad,u16 reg,unsigned int len,u32 * val)117*4882a593Smuzhiyun static int max96714_read_reg(struct vehicle_ad_dev *ad, u16 reg,
118*4882a593Smuzhiyun unsigned int len, u32 *val)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun struct i2c_msg msgs[2];
121*4882a593Smuzhiyun u8 *data_be_p;
122*4882a593Smuzhiyun __be32 data_be = 0;
123*4882a593Smuzhiyun __be16 reg_addr_be = cpu_to_be16(reg);
124*4882a593Smuzhiyun int ret;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (len > 4 || !len)
127*4882a593Smuzhiyun return -EINVAL;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun data_be_p = (u8 *)&data_be;
130*4882a593Smuzhiyun /* Write register address */
131*4882a593Smuzhiyun msgs[0].addr = ad->i2c_add;
132*4882a593Smuzhiyun msgs[0].flags = 0;
133*4882a593Smuzhiyun msgs[0].len = 2;
134*4882a593Smuzhiyun msgs[0].buf = (u8 *)®_addr_be;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* Read data from register */
137*4882a593Smuzhiyun msgs[1].addr = ad->i2c_add;
138*4882a593Smuzhiyun msgs[1].flags = I2C_M_RD;
139*4882a593Smuzhiyun msgs[1].len = len;
140*4882a593Smuzhiyun msgs[1].buf = &data_be_p[4 - len];
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun ret = i2c_transfer(ad->adapter, msgs, ARRAY_SIZE(msgs));
143*4882a593Smuzhiyun if (ret != ARRAY_SIZE(msgs))
144*4882a593Smuzhiyun return -EIO;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun *val = be32_to_cpu(data_be);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
max96714_write_reg(struct vehicle_ad_dev * ad,u16 reg,u8 val)151*4882a593Smuzhiyun static int max96714_write_reg(struct vehicle_ad_dev *ad, u16 reg, u8 val)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun struct i2c_msg msg;
154*4882a593Smuzhiyun u8 buf[3];
155*4882a593Smuzhiyun int ret;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun buf[0] = reg >> 8;
158*4882a593Smuzhiyun buf[1] = reg & 0xff;
159*4882a593Smuzhiyun buf[2] = val;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun msg.addr = ad->i2c_add;
162*4882a593Smuzhiyun msg.flags = 0;
163*4882a593Smuzhiyun msg.buf = buf;
164*4882a593Smuzhiyun msg.len = sizeof(buf);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun ret = i2c_transfer(ad->adapter, &msg, 1);
167*4882a593Smuzhiyun if (ret >= 0)
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun VEHICLE_DGERR(
171*4882a593Smuzhiyun "max96714 write reg(0x%x val:0x%x) failed !\n", reg, val);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return ret;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
max96714_write_array(struct vehicle_ad_dev * ad,const struct regval * regs)176*4882a593Smuzhiyun static int max96714_write_array(struct vehicle_ad_dev *ad,
177*4882a593Smuzhiyun const struct regval *regs)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun u32 i = 0;
180*4882a593Smuzhiyun int ret = 0;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun for (i = 0; ret == 0 && regs[i].reg != REG_NULL; i++)
183*4882a593Smuzhiyun ret = max96714_write_reg(ad, regs[i].reg, regs[i].val);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return ret;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
max96714_reinit_parameter(struct vehicle_ad_dev * ad,unsigned char cvstd)188*4882a593Smuzhiyun static void max96714_reinit_parameter(struct vehicle_ad_dev *ad, unsigned char cvstd)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun int i = 0;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun switch (cvstd) {
193*4882a593Smuzhiyun case CVSTD_1080P30:
194*4882a593Smuzhiyun ad->cfg.width = 1920;
195*4882a593Smuzhiyun ad->cfg.height = 1080;
196*4882a593Smuzhiyun ad->cfg.start_x = 0;
197*4882a593Smuzhiyun ad->cfg.start_y = 0;
198*4882a593Smuzhiyun ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
199*4882a593Smuzhiyun ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
200*4882a593Smuzhiyun ad->cfg.field_order = 0;
201*4882a593Smuzhiyun ad->cfg.yuv_order = 0;/*00 - UYVY*/
202*4882a593Smuzhiyun ad->cfg.href = 0;
203*4882a593Smuzhiyun ad->cfg.vsync = 0;
204*4882a593Smuzhiyun ad->cfg.frame_rate = 30;
205*4882a593Smuzhiyun ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun default:
209*4882a593Smuzhiyun ad->cfg.width = 1920;
210*4882a593Smuzhiyun ad->cfg.height = 1080;
211*4882a593Smuzhiyun ad->cfg.start_x = 0;
212*4882a593Smuzhiyun ad->cfg.start_y = 0;
213*4882a593Smuzhiyun ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
214*4882a593Smuzhiyun ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
215*4882a593Smuzhiyun ad->cfg.field_order = 0;
216*4882a593Smuzhiyun ad->cfg.yuv_order = 0;/*00 - UYVY*/
217*4882a593Smuzhiyun ad->cfg.href = 0;
218*4882a593Smuzhiyun ad->cfg.vsync = 0;
219*4882a593Smuzhiyun ad->cfg.frame_rate = 30;
220*4882a593Smuzhiyun ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun ad->cfg.type = V4L2_MBUS_CSI2_DPHY;
224*4882a593Smuzhiyun ad->cfg.mbus_flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
225*4882a593Smuzhiyun V4L2_MBUS_CSI2_CHANNEL_0;
226*4882a593Smuzhiyun ad->cfg.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8;
227*4882a593Smuzhiyun ad->cfg.dphy_param = &max96714_dcphy_param;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun switch (ad->cfg.mbus_flags & V4L2_MBUS_CSI2_LANES) {
230*4882a593Smuzhiyun case V4L2_MBUS_CSI2_1_LANE:
231*4882a593Smuzhiyun ad->cfg.lanes = 1;
232*4882a593Smuzhiyun break;
233*4882a593Smuzhiyun case V4L2_MBUS_CSI2_2_LANE:
234*4882a593Smuzhiyun ad->cfg.lanes = 2;
235*4882a593Smuzhiyun break;
236*4882a593Smuzhiyun case V4L2_MBUS_CSI2_3_LANE:
237*4882a593Smuzhiyun ad->cfg.lanes = 3;
238*4882a593Smuzhiyun break;
239*4882a593Smuzhiyun case V4L2_MBUS_CSI2_4_LANE:
240*4882a593Smuzhiyun ad->cfg.lanes = 4;
241*4882a593Smuzhiyun break;
242*4882a593Smuzhiyun default:
243*4882a593Smuzhiyun ad->cfg.lanes = 1;
244*4882a593Smuzhiyun break;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* fix crop info from dts config */
248*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
249*4882a593Smuzhiyun if ((ad->defrects[i].width == ad->cfg.width) &&
250*4882a593Smuzhiyun (ad->defrects[i].height == ad->cfg.height)) {
251*4882a593Smuzhiyun ad->cfg.start_x = ad->defrects[i].crop_x;
252*4882a593Smuzhiyun ad->cfg.start_y = ad->defrects[i].crop_y;
253*4882a593Smuzhiyun ad->cfg.width = ad->defrects[i].crop_width;
254*4882a593Smuzhiyun ad->cfg.height = ad->defrects[i].crop_height;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun VEHICLE_DG("crop(%d,%d)", ad->cfg.start_x, ad->cfg.start_y);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
max96714_reg_init(struct vehicle_ad_dev * ad,unsigned char cvstd)261*4882a593Smuzhiyun static void max96714_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun struct regval *sensor;
264*4882a593Smuzhiyun int ret = 0;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun switch (cvstd) {
267*4882a593Smuzhiyun case CVSTD_1080P30:
268*4882a593Smuzhiyun VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
269*4882a593Smuzhiyun sensor = sensor_preview_data_1080p_30hz;
270*4882a593Smuzhiyun break;
271*4882a593Smuzhiyun default:
272*4882a593Smuzhiyun VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
273*4882a593Smuzhiyun sensor = sensor_preview_data_1080p_30hz;
274*4882a593Smuzhiyun break;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun ret = max96714_write_array(ad, sensor);
278*4882a593Smuzhiyun if (ret)
279*4882a593Smuzhiyun VEHICLE_DGERR("%s, init sensor fail", __func__);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
max96714_channel_set(struct vehicle_ad_dev * ad,int channel)282*4882a593Smuzhiyun void max96714_channel_set(struct vehicle_ad_dev *ad, int channel)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
max96714_ad_get_cfg(struct vehicle_cfg ** cfg)286*4882a593Smuzhiyun int max96714_ad_get_cfg(struct vehicle_cfg **cfg)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun if (!max96714_g_addev)
289*4882a593Smuzhiyun return -1;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun switch (cvstd_state) {
292*4882a593Smuzhiyun case VIDEO_UNPLUG:
293*4882a593Smuzhiyun max96714_g_addev->cfg.ad_ready = false;
294*4882a593Smuzhiyun break;
295*4882a593Smuzhiyun case VIDEO_LOCKED:
296*4882a593Smuzhiyun max96714_g_addev->cfg.ad_ready = true;
297*4882a593Smuzhiyun break;
298*4882a593Smuzhiyun case VIDEO_IN:
299*4882a593Smuzhiyun max96714_g_addev->cfg.ad_ready = false;
300*4882a593Smuzhiyun break;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun max96714_g_addev->cfg.ad_ready = true;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun *cfg = &max96714_g_addev->cfg;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
max96714_ad_check_cif_error(struct vehicle_ad_dev * ad,int last_line)310*4882a593Smuzhiyun void max96714_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun VEHICLE_DG("last_line %d\n", last_line);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (last_line < 1)
315*4882a593Smuzhiyun return;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun ad->cif_error_last_line = last_line;
318*4882a593Smuzhiyun if (cvstd_mode == CVSTD_PAL) {
319*4882a593Smuzhiyun if (last_line == FORCE_NTSC_HEIGHT) {
320*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq)
321*4882a593Smuzhiyun queue_delayed_work(
322*4882a593Smuzhiyun ad->state_check_work.state_check_wq,
323*4882a593Smuzhiyun &ad->state_check_work.work,
324*4882a593Smuzhiyun msecs_to_jiffies(0));
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun } else if (cvstd_mode == CVSTD_NTSC) {
327*4882a593Smuzhiyun if (last_line == FORCE_PAL_HEIGHT) {
328*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq)
329*4882a593Smuzhiyun queue_delayed_work(
330*4882a593Smuzhiyun ad->state_check_work.state_check_wq,
331*4882a593Smuzhiyun &ad->state_check_work.work,
332*4882a593Smuzhiyun msecs_to_jiffies(0));
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun } else if (cvstd_mode == CVSTD_1080P30) {
335*4882a593Smuzhiyun if (last_line == FORCE_1080P_HEIGHT) {
336*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq)
337*4882a593Smuzhiyun queue_delayed_work(
338*4882a593Smuzhiyun ad->state_check_work.state_check_wq,
339*4882a593Smuzhiyun &ad->state_check_work.work,
340*4882a593Smuzhiyun msecs_to_jiffies(0));
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
max96714_check_id(struct vehicle_ad_dev * ad)345*4882a593Smuzhiyun int max96714_check_id(struct vehicle_ad_dev *ad)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun int ret = 0;
348*4882a593Smuzhiyun u32 pid = 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun ret = max96714_read_reg(ad, MAX96714_CHIP_ID_REG, SENSOR_VALUE_LEN, &pid);
351*4882a593Smuzhiyun if (pid != MAX96714_CHIP_ID) {
352*4882a593Smuzhiyun VEHICLE_DGERR("%s: expected 0xC9, detected: 0x%02x !",
353*4882a593Smuzhiyun ad->ad_name, pid);
354*4882a593Smuzhiyun ret = -EINVAL;
355*4882a593Smuzhiyun } else {
356*4882a593Smuzhiyun VEHICLE_INFO("Found MAX96714 sensor: id(0x%2x) !\n", pid);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return ret;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
max96714_check_cvstd(struct vehicle_ad_dev * ad,bool activate_check)362*4882a593Smuzhiyun static int max96714_check_cvstd(struct vehicle_ad_dev *ad, bool activate_check)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun static int state = VIDEO_UNPLUG;
365*4882a593Smuzhiyun int ret = 0;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun ret = max96714_read_reg(ad, MAX96714_GMSL_STATE, SENSOR_VALUE_LEN, &state);
368*4882a593Smuzhiyun if (ret)
369*4882a593Smuzhiyun VEHICLE_DGERR("read GMSL2 link lock failed!\n");
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (state & FLAG_LOCKED) {
372*4882a593Smuzhiyun state = VIDEO_LOCKED;
373*4882a593Smuzhiyun VEHICLE_DG("GMSL2 link locked!\n");
374*4882a593Smuzhiyun cvstd_mode = CVSTD_1080P30;
375*4882a593Smuzhiyun } else {
376*4882a593Smuzhiyun state = VIDEO_UNPLUG;
377*4882a593Smuzhiyun VEHICLE_DG("GMSL2 link not locked!\n");
378*4882a593Smuzhiyun cvstd_mode = cvstd_old;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
max96714_stream(struct vehicle_ad_dev * ad,int enable)384*4882a593Smuzhiyun int max96714_stream(struct vehicle_ad_dev *ad, int enable)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun VEHICLE_INFO("%s on(%d)\n", __func__, enable);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun g_max96714_streaming = (enable != 0);
389*4882a593Smuzhiyun if (g_max96714_streaming) {
390*4882a593Smuzhiyun max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_STREAMING);
391*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq)
392*4882a593Smuzhiyun queue_delayed_work(ad->state_check_work.state_check_wq,
393*4882a593Smuzhiyun &ad->state_check_work.work, msecs_to_jiffies(200));
394*4882a593Smuzhiyun } else {
395*4882a593Smuzhiyun max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_SW_STANDBY);
396*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq)
397*4882a593Smuzhiyun cancel_delayed_work_sync(&ad->state_check_work.work);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
max96714_power_on(struct vehicle_ad_dev * ad)403*4882a593Smuzhiyun static void max96714_power_on(struct vehicle_ad_dev *ad)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun /* gpio_direction_output(ad->power, ad->pwr_active); */
406*4882a593Smuzhiyun if (gpio_is_valid(ad->power)) {
407*4882a593Smuzhiyun gpio_request(ad->power, "max96714_power");
408*4882a593Smuzhiyun gpio_direction_output(ad->power, ad->pwr_active);
409*4882a593Smuzhiyun /* gpio_set_value(ad->power, ad->pwr_active); */
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun if (gpio_is_valid(ad->powerdown)) {
413*4882a593Smuzhiyun gpio_request(ad->powerdown, "max96714_pwd");
414*4882a593Smuzhiyun gpio_direction_output(ad->powerdown, 1);
415*4882a593Smuzhiyun /* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (gpio_is_valid(ad->reset)) {
419*4882a593Smuzhiyun gpio_request(ad->reset, "max96714_rst");
420*4882a593Smuzhiyun gpio_direction_output(ad->reset, 0);
421*4882a593Smuzhiyun usleep_range(1500, 2000);
422*4882a593Smuzhiyun gpio_direction_output(ad->reset, 1);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
max96714_power_deinit(struct vehicle_ad_dev * ad)426*4882a593Smuzhiyun static void max96714_power_deinit(struct vehicle_ad_dev *ad)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun if (gpio_is_valid(ad->reset))
429*4882a593Smuzhiyun gpio_free(ad->reset);
430*4882a593Smuzhiyun if (gpio_is_valid(ad->power))
431*4882a593Smuzhiyun gpio_free(ad->power);
432*4882a593Smuzhiyun if (gpio_is_valid(ad->powerdown))
433*4882a593Smuzhiyun gpio_free(ad->powerdown);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
max96714_check_state_work(struct work_struct * work)436*4882a593Smuzhiyun static void max96714_check_state_work(struct work_struct *work)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun struct vehicle_ad_dev *ad;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun ad = max96714_g_addev;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (ad->cif_error_last_line > 0) {
443*4882a593Smuzhiyun max96714_check_cvstd(ad, true);
444*4882a593Smuzhiyun ad->cif_error_last_line = 0;
445*4882a593Smuzhiyun } else {
446*4882a593Smuzhiyun max96714_check_cvstd(ad, false);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun VEHICLE_DG("%s:cvstd_old(%d), cvstd_mode(%d)\n", __func__, cvstd_old, cvstd_mode);
450*4882a593Smuzhiyun if (cvstd_old != cvstd_mode || cvstd_old_state != cvstd_state) {
451*4882a593Smuzhiyun VEHICLE_INFO("%s:ad sensor std mode change, cvstd_old(%d), cvstd_mode(%d)\n",
452*4882a593Smuzhiyun __func__, cvstd_old, cvstd_mode);
453*4882a593Smuzhiyun cvstd_old = cvstd_mode;
454*4882a593Smuzhiyun cvstd_old_state = cvstd_state;
455*4882a593Smuzhiyun max96714_reinit_parameter(ad, cvstd_mode);
456*4882a593Smuzhiyun max96714_reg_init(ad, cvstd_mode);
457*4882a593Smuzhiyun vehicle_ad_stat_change_notify();
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun if (g_max96714_streaming) {
460*4882a593Smuzhiyun queue_delayed_work(ad->state_check_work.state_check_wq,
461*4882a593Smuzhiyun &ad->state_check_work.work, msecs_to_jiffies(100));
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
max96714_ad_deinit(void)465*4882a593Smuzhiyun int max96714_ad_deinit(void)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun struct vehicle_ad_dev *ad;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun ad = max96714_g_addev;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun if (!ad)
472*4882a593Smuzhiyun return -ENODEV;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (ad->state_check_work.state_check_wq) {
475*4882a593Smuzhiyun cancel_delayed_work_sync(&ad->state_check_work.work);
476*4882a593Smuzhiyun flush_delayed_work(&ad->state_check_work.work);
477*4882a593Smuzhiyun flush_workqueue(ad->state_check_work.state_check_wq);
478*4882a593Smuzhiyun destroy_workqueue(ad->state_check_work.state_check_wq);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun if (ad->irq)
481*4882a593Smuzhiyun free_irq(ad->irq, ad);
482*4882a593Smuzhiyun max96714_power_deinit(ad);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
get_ad_mode_from_fix_format(int fix_format)487*4882a593Smuzhiyun static __maybe_unused int get_ad_mode_from_fix_format(int fix_format)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun int mode = -1;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun switch (fix_format) {
492*4882a593Smuzhiyun case AD_FIX_FORMAT_PAL:
493*4882a593Smuzhiyun case AD_FIX_FORMAT_NTSC:
494*4882a593Smuzhiyun case AD_FIX_FORMAT_720P_50FPS:
495*4882a593Smuzhiyun case AD_FIX_FORMAT_720P_30FPS:
496*4882a593Smuzhiyun case AD_FIX_FORMAT_720P_25FPS:
497*4882a593Smuzhiyun mode = CVSTD_720P25;
498*4882a593Smuzhiyun break;
499*4882a593Smuzhiyun case AD_FIX_FORMAT_1080P_30FPS:
500*4882a593Smuzhiyun case AD_FIX_FORMAT_1080P_25FPS:
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun default:
503*4882a593Smuzhiyun mode = CVSTD_1080P30;
504*4882a593Smuzhiyun break;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return mode;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
max96714_ad_init(struct vehicle_ad_dev * ad)510*4882a593Smuzhiyun int max96714_ad_init(struct vehicle_ad_dev *ad)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun max96714_g_addev = ad;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* 1. i2c init */
515*4882a593Smuzhiyun while (ad->adapter == NULL) {
516*4882a593Smuzhiyun ad->adapter = i2c_get_adapter(ad->i2c_chl);
517*4882a593Smuzhiyun usleep_range(10000, 12000);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun if (ad->adapter == NULL)
520*4882a593Smuzhiyun return -ENODEV;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
523*4882a593Smuzhiyun return -EIO;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun max96714_power_on(ad);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun max96714_reg_init(ad, cvstd_mode);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun max96714_reinit_parameter(ad, cvstd_mode);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun INIT_DELAYED_WORK(&ad->state_check_work.work, max96714_check_state_work);
532*4882a593Smuzhiyun ad->state_check_work.state_check_wq =
533*4882a593Smuzhiyun create_singlethread_workqueue("vehicle-ad-max96714");
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun queue_delayed_work(ad->state_check_work.state_check_wq,
536*4882a593Smuzhiyun &ad->state_check_work.work, msecs_to_jiffies(100));
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return 0;
539*4882a593Smuzhiyun }
540