hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/media/i2c/jaguar1_drv/jaguar1_v4l2.c
....@@ -3,6 +3,7 @@
33 * jaguar1 driver
44 * V0.0X01.0X00 first version.
55 * V0.0X01.0X01 fix kernel5.10 compile error.
6
+ * V0.0X01.0X02 add workqueue to detect ahd state.
67 *
78 */
89
....@@ -41,7 +42,19 @@
4142 #include "jaguar1_drv.h"
4243 #include "jaguar1_v4l2.h"
4344
44
-#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x1)
45
+#define WORK_QUEUE
46
+
47
+#ifdef WORK_QUEUE
48
+#include <linux/workqueue.h>
49
+
50
+struct sensor_state_check_work {
51
+ struct workqueue_struct *state_check_wq;
52
+ struct delayed_work d_work;
53
+};
54
+
55
+#endif
56
+
57
+#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x2)
4558
4659 #ifndef V4L2_CID_DIGITAL_GAIN
4760 #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
....@@ -104,6 +117,12 @@
104117 unsigned int height;
105118 };
106119
120
+enum jaguar1_hot_plug_state {
121
+ PLUG_IN = 0,
122
+ PLUG_OUT,
123
+ PLUG_STATE_MAX,
124
+};
125
+
107126 struct jaguar1 {
108127 struct i2c_client *client;
109128 struct clk *xvclk;
....@@ -134,6 +153,16 @@
134153 const struct jaguar1_framesize *frame_size;
135154 int streaming;
136155 struct jaguar1_default_rect defrect;
156
+#ifdef WORK_QUEUE
157
+ struct sensor_state_check_work plug_state_check;
158
+ u8 cur_detect_status;
159
+ u8 last_detect_status;
160
+ u64 timestamp0;
161
+ u64 timestamp1;
162
+#endif
163
+ bool hot_plug;
164
+ u8 is_reset;
165
+ struct semaphore reg_sem;
137166 };
138167
139168 #define to_jaguar1(sd) container_of(sd, struct jaguar1, subdev)
....@@ -212,6 +241,63 @@
212241 static const s64 link_freq_menu_items[] = {
213242 JAGUAR1_LINK_FREQ
214243 };
244
+
245
+/* sensor register write */
246
+static int jaguar1_write(struct i2c_client *client, u8 reg, u8 val)
247
+{
248
+ struct i2c_msg msg;
249
+ u8 buf[2];
250
+ int ret;
251
+
252
+ dev_dbg(&client->dev, "write reg(0x%x val:0x%x)!\n", reg, val);
253
+ buf[0] = reg & 0xFF;
254
+ buf[1] = val;
255
+
256
+ msg.addr = client->addr;
257
+ msg.flags = client->flags;
258
+ msg.buf = buf;
259
+ msg.len = sizeof(buf);
260
+
261
+ ret = i2c_transfer(client->adapter, &msg, 1);
262
+ if (ret >= 0)
263
+ return 0;
264
+
265
+ dev_err(&client->dev,
266
+ "jaguar1 write reg(0x%x val:0x%x) failed !\n", reg, val);
267
+
268
+ return ret;
269
+}
270
+
271
+/* sensor register read */
272
+static int jaguar1_read(struct i2c_client *client, u8 reg, u8 *val)
273
+{
274
+ struct i2c_msg msg[2];
275
+ u8 buf[1];
276
+ int ret;
277
+
278
+ buf[0] = reg & 0xFF;
279
+
280
+ msg[0].addr = client->addr;
281
+ msg[0].flags = client->flags;
282
+ msg[0].buf = buf;
283
+ msg[0].len = sizeof(buf);
284
+
285
+ msg[1].addr = client->addr;
286
+ msg[1].flags = client->flags | I2C_M_RD;
287
+ msg[1].buf = buf;
288
+ msg[1].len = 1;
289
+
290
+ ret = i2c_transfer(client->adapter, msg, 2);
291
+ if (ret >= 0) {
292
+ *val = buf[0];
293
+ return 0;
294
+ }
295
+
296
+ dev_err(&client->dev, "jaguar1 read reg(0x%x) failed !\n", reg);
297
+
298
+ return ret;
299
+}
300
+
215301 static int __jaguar1_power_on(struct jaguar1 *jaguar1)
216302 {
217303 u32 i;
....@@ -340,7 +426,7 @@
340426 struct jaguar1 *jaguar1 = to_jaguar1(sd);
341427 int ret = 0;
342428
343
- dev_dbg(&client->dev, "%s: on %d\n", __func__, on);
429
+ dev_info(&client->dev, "%s: on %d\n", __func__, on);
344430 mutex_lock(&jaguar1->mutex);
345431
346432 /* If the power state is not modified - no work to do. */
....@@ -351,11 +437,12 @@
351437 ret = __jaguar1_power_on(jaguar1);
352438 if (ret < 0)
353439 goto exit;
354
-
355440 jaguar1->power_on = true;
441
+
356442 } else {
357443 __jaguar1_power_off(jaguar1);
358444 jaguar1->power_on = false;
445
+
359446 }
360447
361448 exit:
....@@ -430,6 +517,7 @@
430517 format->field = match->field;
431518 }
432519
520
+static inline bool jaguar1_no_signal(struct v4l2_subdev *sd, u8 *novid);
433521 static int jaguar1_stream(struct v4l2_subdev *sd, int on)
434522 {
435523 struct i2c_client *client = v4l2_get_subdevdata(sd);
....@@ -438,7 +526,7 @@
438526 enum NC_VIVO_CH_FORMATDEF fmt_idx;
439527 int ch;
440528
441
- dev_dbg(&client->dev, "%s: on %d\n", __func__, on);
529
+ dev_info(&client->dev, "%s: on %d\n", __func__, on);
442530 mutex_lock(&jaguar1->mutex);
443531 on = !!on;
444532
....@@ -455,8 +543,35 @@
455543 video_init.ch_param[ch].interface = YUV_422;
456544 }
457545 jaguar1_start(&video_init);
546
+#ifdef WORK_QUEUE
547
+ jaguar1->hot_plug = false;
548
+ jaguar1->is_reset = 0;
549
+ usleep_range(20000, 21000);
550
+ /* get power on state first*/
551
+ jaguar1_no_signal(sd, &jaguar1->last_detect_status);
552
+ /* check hot plug state */
553
+ if (jaguar1->plug_state_check.state_check_wq) {
554
+ dev_info(&client->dev, "%s queue_delayed_work 1000ms", __func__);
555
+ queue_delayed_work(jaguar1->plug_state_check.state_check_wq,
556
+ &jaguar1->plug_state_check.d_work,
557
+ msecs_to_jiffies(1000));
558
+ }
559
+ jaguar1->timestamp0 = ktime_get_ns();
560
+#endif
458561 } else {
459562 jaguar1_stop();
563
+#ifdef WORK_QUEUE
564
+ jaguar1->timestamp1 = ktime_get_ns();
565
+ /* if stream off & on interval too short, do repower */
566
+ if (div_u64((jaguar1->timestamp1 - jaguar1->timestamp0), 1000000) < 1200) {
567
+ dev_info(&client->dev, "stream on/off too short, do power off & on!");
568
+ __jaguar1_power_off(jaguar1);
569
+ usleep_range(40000, 41000);
570
+ __jaguar1_power_on(jaguar1);
571
+ }
572
+ cancel_delayed_work_sync(&jaguar1->plug_state_check.d_work);
573
+ dev_info(&client->dev, "cancle_queue_delayed_work");
574
+#endif
460575 }
461576
462577 jaguar1->streaming = on;
....@@ -505,12 +620,144 @@
505620 return 0;
506621 }
507622
623
+/* indicate N4 no signal channel */
624
+static inline bool jaguar1_no_signal(struct v4l2_subdev *sd, u8 *novid)
625
+{
626
+ struct jaguar1 *jaguar1 = to_jaguar1(sd);
627
+ struct i2c_client *client = jaguar1->client;
628
+ u8 videoloss = 0;
629
+ u8 temp = 0;
630
+ int ch, ret;
631
+ bool no_signal = false;
632
+
633
+ jaguar1_write(client, 0xff, 0x00);
634
+ for (ch = 0 ; ch < 4; ch++) {
635
+ ret = jaguar1_read(client, 0xa4 + ch, &temp);
636
+ if (ret < 0)
637
+ dev_err(&client->dev, "Failed to read videoloss state!\n");
638
+ videoloss |= (temp << ch);
639
+ }
640
+ *novid = videoloss;
641
+ dev_dbg(&client->dev, "%s: video loss status:0x%x.\n", __func__, videoloss);
642
+ if (videoloss == 0xf) {
643
+ dev_dbg(&client->dev, "%s: all channels No Video detected.\n", __func__);
644
+ no_signal = true;
645
+ } else {
646
+ dev_dbg(&client->dev, "%s: channel has some video detection.\n", __func__);
647
+ no_signal = false;
648
+ }
649
+ return no_signal;
650
+}
651
+
652
+/* indicate N4 channel locked status */
653
+static inline bool jaguar1_sync(struct v4l2_subdev *sd, u8 *lock_st)
654
+{
655
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
656
+ u8 video_lock_status = 0;
657
+ u8 temp = 0;
658
+ int ch, ret;
659
+ bool has_sync = false;
660
+
661
+ jaguar1_write(client, 0xff, 0x00);
662
+ for (ch = 0 ; ch < 4; ch++) {
663
+ ret = jaguar1_read(client, 0xd0 + ch, &temp);
664
+ if (ret < 0)
665
+ dev_err(&client->dev, "Failed to read LOCK status!\n");
666
+ video_lock_status |= (temp << ch);
667
+ }
668
+
669
+ dev_dbg(&client->dev, "%s: video AGC LOCK status:0x%x.\n",
670
+ __func__, video_lock_status);
671
+ *lock_st = video_lock_status;
672
+ if (video_lock_status) {
673
+ dev_dbg(&client->dev, "%s: channel has AGC LOCK.\n", __func__);
674
+ has_sync = true;
675
+ } else {
676
+ dev_dbg(&client->dev, "%s: channel has no AGC LOCK.\n", __func__);
677
+ has_sync = false;
678
+ }
679
+ return has_sync;
680
+}
681
+
682
+#ifdef WORK_QUEUE
683
+static void jaguar1_plug_state_check_work(struct work_struct *work)
684
+{
685
+ struct sensor_state_check_work *params_check =
686
+ container_of(work, struct sensor_state_check_work, d_work.work);
687
+ struct jaguar1 *jaguar1 =
688
+ container_of(params_check, struct jaguar1, plug_state_check);
689
+ struct i2c_client *client = jaguar1->client;
690
+ struct v4l2_subdev *sd = &jaguar1->subdev;
691
+ u8 novid_status = 0x00;
692
+ u8 sync_status = 0x00;
693
+
694
+ down(&jaguar1->reg_sem);
695
+ jaguar1_no_signal(sd, &novid_status);
696
+ jaguar1_sync(sd, &sync_status);
697
+ up(&jaguar1->reg_sem);
698
+ jaguar1->cur_detect_status = novid_status;
699
+
700
+ /* detect state change to determine is there has plug motion */
701
+ novid_status = jaguar1->cur_detect_status ^ jaguar1->last_detect_status;
702
+ if (novid_status)
703
+ jaguar1->hot_plug = true;
704
+ else
705
+ jaguar1->hot_plug = false;
706
+ jaguar1->last_detect_status = jaguar1->cur_detect_status;
707
+
708
+ if (jaguar1->hot_plug)
709
+ dev_info(&client->dev, "%s has plug motion? (%s)", __func__,
710
+ jaguar1->hot_plug ? "true" : "false");
711
+ if (jaguar1->hot_plug) {
712
+ dev_dbg(&client->dev, "queue_delayed_work 1500ms, if has hot plug motion.");
713
+ queue_delayed_work(jaguar1->plug_state_check.state_check_wq,
714
+ &jaguar1->plug_state_check.d_work, msecs_to_jiffies(1500));
715
+ jaguar1_write(client, 0xFF, 0x20);
716
+ jaguar1_write(client, 0x00, 0x00);
717
+ //jaguar1_write(client, 0x00, (sync_status << 4) | sync_status);
718
+ usleep_range(3000, 5000);
719
+ jaguar1_write(client, 0x00, 0xFF);
720
+ } else {
721
+ dev_dbg(&client->dev, "queue_delayed_work 100ms, if no hot plug motion.");
722
+ queue_delayed_work(jaguar1->plug_state_check.state_check_wq,
723
+ &jaguar1->plug_state_check.d_work, msecs_to_jiffies(100));
724
+ }
725
+}
726
+#endif
727
+
728
+static int jaguar1_g_input_status(struct v4l2_subdev *sd, u32 *status)
729
+{
730
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
731
+ struct jaguar1 *jaguar1 = to_jaguar1(sd);
732
+ int ret;
733
+ u8 temp_novid;
734
+ u8 temp_lock_st;
735
+
736
+ if (!jaguar1->power_on) {
737
+ ret = __jaguar1_power_on(jaguar1);
738
+ if (ret < 0)
739
+ goto exit;
740
+ usleep_range(40000, 50000);
741
+ jaguar1->power_on = true;
742
+ }
743
+
744
+ *status = 0;
745
+ *status |= jaguar1_no_signal(sd, &temp_novid) ? V4L2_IN_ST_NO_SIGNAL : 0;
746
+ *status |= jaguar1_sync(sd, &temp_lock_st) ? 0 : V4L2_IN_ST_NO_SYNC;
747
+
748
+ dev_info(&client->dev, "%s: status = 0x%x\n", __func__, *status);
749
+
750
+exit:
751
+ return 0;
752
+}
753
+
508754 static int jaguar1_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
509755 struct v4l2_mbus_config *cfg)
510756 {
511757 cfg->type = V4L2_MBUS_CSI2_DPHY;
512758 cfg->flags = V4L2_MBUS_CSI2_4_LANE |
513
- V4L2_MBUS_CSI2_CHANNELS;
759
+ V4L2_MBUS_CSI2_CHANNELS |
760
+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
514761
515762 return 0;
516763 }
....@@ -660,17 +907,67 @@
660907 strlcpy(inf->base.lens, jaguar1->len_name, sizeof(inf->base.lens));
661908 }
662909
910
+static void jaguar1_get_vicap_rst_inf(struct jaguar1 *jaguar1,
911
+ struct rkmodule_vicap_reset_info *rst_info)
912
+{
913
+ struct i2c_client *client = jaguar1->client;
914
+
915
+ rst_info->is_reset = jaguar1->hot_plug;
916
+ jaguar1->hot_plug = false;
917
+ rst_info->src = RKCIF_RESET_SRC_ERR_HOTPLUG;
918
+ if (rst_info->is_reset)
919
+ dev_info(&client->dev, "%s: rst_info->is_reset:%d.\n",
920
+ __func__, rst_info->is_reset);
921
+}
922
+
923
+static void jaguar1_set_vicap_rst_inf(struct jaguar1 *jaguar1,
924
+ struct rkmodule_vicap_reset_info rst_info)
925
+{
926
+ jaguar1->is_reset = rst_info.is_reset;
927
+ jaguar1->hot_plug = rst_info.is_reset;
928
+}
929
+
930
+static void jaguar1_set_streaming(struct jaguar1 *jaguar1, int on)
931
+{
932
+ struct i2c_client *client = jaguar1->client;
933
+
934
+
935
+ dev_info(&client->dev, "%s: on: %d\n", __func__, on);
936
+ down(&jaguar1->reg_sem);
937
+ if (on) {
938
+ /* enter mipi clk normal operation */
939
+ jaguar1_write(client, 0xff, 0x21);
940
+ jaguar1_write(client, 0x46, 0x00);
941
+ } else {
942
+ /* enter mipi clk powerdown */
943
+ jaguar1_write(client, 0xff, 0x21);
944
+ jaguar1_write(client, 0x46, 0x01);
945
+ }
946
+ up(&jaguar1->reg_sem);
947
+}
948
+
663949 static long jaguar1_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
664950 {
665951 struct jaguar1 *jaguar1 = to_jaguar1(sd);
666952 long ret = 0;
953
+ u32 stream = 0;
667954
668955 switch (cmd) {
669956 case RKMODULE_GET_MODULE_INFO:
670957 jaguar1_get_module_inf(jaguar1, (struct rkmodule_inf *)arg);
671958 break;
959
+ case RKMODULE_GET_VICAP_RST_INFO:
960
+ jaguar1_get_vicap_rst_inf(jaguar1, (struct rkmodule_vicap_reset_info *)arg);
961
+ break;
962
+ case RKMODULE_SET_VICAP_RST_INFO:
963
+ jaguar1_set_vicap_rst_inf(jaguar1, *(struct rkmodule_vicap_reset_info *)arg);
964
+ break;
672965 case RKMODULE_GET_START_STREAM_SEQ:
673966 *(int *)arg = RKMODULE_START_STREAM_FRONT;
967
+ break;
968
+ case RKMODULE_SET_QUICK_STREAM:
969
+ stream = *((u32 *)arg);
970
+ jaguar1_set_streaming(jaguar1, !!stream);
674971 break;
675972 default:
676973 ret = -ENOTTY;
....@@ -687,8 +984,10 @@
687984 void __user *up = compat_ptr(arg);
688985 struct rkmodule_inf *inf;
689986 struct rkmodule_awb_cfg *cfg;
987
+ struct rkmodule_vicap_reset_info *vicap_rst_inf;
690988 long ret;
691989 int *seq;
990
+ u32 stream = 0;
692991
693992 switch (cmd) {
694993 case RKMODULE_GET_MODULE_INFO:
....@@ -720,6 +1019,35 @@
7201019 ret = -EFAULT;
7211020 kfree(cfg);
7221021 break;
1022
+ case RKMODULE_GET_VICAP_RST_INFO:
1023
+ vicap_rst_inf = kzalloc(sizeof(*vicap_rst_inf), GFP_KERNEL);
1024
+ if (!vicap_rst_inf) {
1025
+ ret = -ENOMEM;
1026
+ return ret;
1027
+ }
1028
+
1029
+ ret = jaguar1_ioctl(sd, cmd, vicap_rst_inf);
1030
+ if (!ret) {
1031
+ ret = copy_to_user(up, vicap_rst_inf, sizeof(*vicap_rst_inf));
1032
+ if (ret)
1033
+ ret = -EFAULT;
1034
+ }
1035
+ kfree(vicap_rst_inf);
1036
+ break;
1037
+ case RKMODULE_SET_VICAP_RST_INFO:
1038
+ vicap_rst_inf = kzalloc(sizeof(*vicap_rst_inf), GFP_KERNEL);
1039
+ if (!vicap_rst_inf) {
1040
+ ret = -ENOMEM;
1041
+ return ret;
1042
+ }
1043
+
1044
+ ret = copy_from_user(vicap_rst_inf, up, sizeof(*vicap_rst_inf));
1045
+ if (!ret)
1046
+ ret = jaguar1_ioctl(sd, cmd, vicap_rst_inf);
1047
+ else
1048
+ ret = -EFAULT;
1049
+ kfree(vicap_rst_inf);
1050
+ break;
7231051 case RKMODULE_GET_START_STREAM_SEQ:
7241052 seq = kzalloc(sizeof(*seq), GFP_KERNEL);
7251053 if (!seq) {
....@@ -734,6 +1062,13 @@
7341062 ret = -EFAULT;
7351063 }
7361064 kfree(seq);
1065
+ break;
1066
+ case RKMODULE_SET_QUICK_STREAM:
1067
+ ret = copy_from_user(&stream, up, sizeof(u32));
1068
+ if (!ret)
1069
+ ret = jaguar1_ioctl(sd, cmd, &stream);
1070
+ else
1071
+ ret = -EFAULT;
7371072 break;
7381073 default:
7391074 ret = -ENOIOCTLCMD;
....@@ -770,6 +1105,7 @@
7701105 };
7711106
7721107 static const struct v4l2_subdev_video_ops jaguar1_video_ops = {
1108
+ .g_input_status = jaguar1_g_input_status,
7731109 .s_stream = jaguar1_stream,
7741110 .g_frame_interval = jaguar1_g_frame_interval,
7751111 };
....@@ -984,7 +1320,7 @@
9841320 }
9851321
9861322 __jaguar1_power_on(jaguar1);
987
- ret = jaguar1_init(i2c_adapter_id(client->adapter));
1323
+ ret |= jaguar1_init(i2c_adapter_id(client->adapter));
9881324 if (ret) {
9891325 dev_err(dev, "Failed to init jaguar1\n");
9901326 __jaguar1_power_off(jaguar1);
....@@ -992,7 +1328,7 @@
9921328
9931329 return ret;
9941330 }
995
-
1331
+ sema_init(&jaguar1->reg_sem, 1);
9961332 #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
9971333 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
9981334 #endif
....@@ -1034,6 +1370,22 @@
10341370
10351371 v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
10361372 client->addr << 1, client->adapter->name);
1373
+#ifdef WORK_QUEUE
1374
+ /* init work_queue for state_check */
1375
+ INIT_DELAYED_WORK(&jaguar1->plug_state_check.d_work, jaguar1_plug_state_check_work);
1376
+ jaguar1->plug_state_check.state_check_wq =
1377
+ create_singlethread_workqueue("jaguar1_work_queue");
1378
+ if (jaguar1->plug_state_check.state_check_wq == NULL) {
1379
+ dev_err(dev, "%s(%d): %s create failed.\n", __func__, __LINE__,
1380
+ "jaguar1_work_queue");
1381
+ }
1382
+ jaguar1->cur_detect_status = 0x0;
1383
+ jaguar1->last_detect_status = 0x0;
1384
+ jaguar1->hot_plug = false;
1385
+ jaguar1->is_reset = 0;
1386
+
1387
+#endif
1388
+
10371389 return 0;
10381390
10391391 err_power_off:
....@@ -1060,7 +1412,10 @@
10601412 if (!pm_runtime_status_suspended(&client->dev))
10611413 __jaguar1_power_off(jaguar1);
10621414 pm_runtime_set_suspended(&client->dev);
1063
-
1415
+#ifdef WORK_QUEUE
1416
+ if (jaguar1->plug_state_check.state_check_wq != NULL)
1417
+ destroy_workqueue(jaguar1->plug_state_check.state_check_wq);
1418
+#endif
10641419 return 0;
10651420 }
10661421