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