一、原理图,接口比较简单,就是I2C。
二、光感用轮询方式,距离用中断方式。代码。
1、dts配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27ls_stk3x1x: light@48 { compatible = "ls_stk3x1x"; status = "okay"; reg = <0x48>; type = <SENSOR_TYPE_LIGHT>; irq_enable = <0>; als_threshold_high = <100>; als_threshold_low = <10>; als_ctrl_gain = <2>; /* 0:x1 1:x4 2:x16 3:x64 */ poll_delay_ms = <100>; layout = <1>; }; ps_stk3x1x: proximity@48 { compatible = "ps_stk3x1x"; status = "okay"; reg = <0x48>; type = <SENSOR_TYPE_PROXIMITY>; pinctrl-names = "default"; pinctrl-0 = <&al_det>; irq-gpio = <&gpio0 RK_PD4 IRQ_TYPE_LEVEL_LOW>; irq_enable = <1>; ps_threshold_high = <0x200>; ps_threshold_low = <0x100>; ps_ctrl_gain = <3>; /* 0:x1 1:x4 2:x16 3:x64 */ ps_led_current = <3>; /* 0:12.5mA 1:25mA 2:50mA 3:100mA */ poll_delay_ms = <100>; };
2、光感驱动代码 kerneldriversinputsensorslsensorls_stk3x1x.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907/* * ls_stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x * proximity/ambient light sensor * * Copyright (C) 2012~2015 Lex Hsieh / sensortek <lex_hsieh@sensortek.com.tw> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/input.h> #include <linux/workqueue.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/errno.h> #include <linux/wakelock.h> #include <linux/interrupt.h> #include <linux/gpio.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/sensor-dev.h> #include <linux/of_gpio.h> #include <linux/regulator/consumer.h> #ifdef CONFIG_HAS_EARLYSUSPEND //#include <linux/earlysuspend.h> #endif #include "linux/stk3x1x.h" #define DRIVER_VERSION "3.10.0_0429" /* Driver Settings */ #define STK_POLL_ALS /* ALS interrupt is valid only when STK_PS_INT_MODE = 1 or 4*/ // #define STK_IRS #define STK_DEBUG_PRINTF #define PROXIMITY_ID_I2C 2 /*****************************************************************************/ /* Define Register Map */ #define STK_STATE_REG 0x00 #define STK_PSCTRL_REG 0x01 #define STK_ALSCTRL_REG 0x02 #define STK_LEDCTRL_REG 0x03 #define STK_INT_REG 0x04 #define STK_WAIT_REG 0x05 #define STK_THDH1_PS_REG 0x06 #define STK_THDH2_PS_REG 0x07 #define STK_THDL1_PS_REG 0x08 #define STK_THDL2_PS_REG 0x09 #define STK_THDH1_ALS_REG 0x0A #define STK_THDH2_ALS_REG 0x0B #define STK_THDL1_ALS_REG 0x0C #define STK_THDL2_ALS_REG 0x0D #define STK_FLAG_REG 0x10 #define STK_DATA1_PS_REG 0x11 #define STK_DATA2_PS_REG 0x12 #define STK_DATA1_ALS_REG 0x13 #define STK_DATA2_ALS_REG 0x14 #define STK_DATA1_OFFSET_REG 0x15 #define STK_DATA2_OFFSET_REG 0x16 #define STK_DATA1_IR_REG 0x17 #define STK_DATA2_IR_REG 0x18 #define STK_PDT_ID_REG 0x3E #define STK_RSRVD_REG 0x3F #define STK_SW_RESET_REG 0x80 #define STK_STATE_EN_IRS_MASK 0x80 #define STK_STATE_EN_AK_MASK 0x40 #define STK_STATE_EN_ASO_MASK 0x20 #define STK_STATE_EN_IRO_MASK 0x10 #define STK_STATE_EN_WAIT_MASK 0x04 #define STK_STATE_EN_ALS_MASK 0x02 #define STK_STATE_EN_PS_MASK 0x01 #define STK_FLG_ALSDR_MASK 0x80 #define STK_FLG_PSDR_MASK 0x40 #define STK_FLG_ALSINT_MASK 0x20 #define STK_FLG_PSINT_MASK 0x10 #define STK_FLG_OUI_MASK 0x04 #define STK_FLG_IR_RDY_MASK 0x02 #define STK_FLG_NF_MASK 0x01 #define STK_INT_ALS 0x08 #define STK_IRC_MAX_ALS_CODE 20000 #define STK_IRC_MIN_ALS_CODE 25 #define STK_IRC_MIN_IR_CODE 50 #define STK_IRC_ALS_DENOMI 2 #define STK_IRC_ALS_NUMERA 5 #define STK_IRC_ALS_CORREC 850 #define STK_IRS_IT_REDUCE 2 #define STK_ALS_READ_IRS_IT_REDUCE 5 #define STK_ALS_THRESHOLD 30 /*****************************************************************************/ #define STK3310SA_PID 0x17 #define STK3311SA_PID 0x1E #define STK3311WV_PID 0x1D /*****************************************************************************/ #ifdef STK_ALS_FIR #define STK_FIR_LEN 8 #define MAX_FIR_LEN 32 struct data_filter { u16 raw[MAX_FIR_LEN]; int sum; int number; int idx; }; #endif struct stk3x1x_data { uint16_t ir_code; uint16_t als_correct_factor; uint8_t alsctrl_reg; uint8_t psctrl_reg; uint8_t ledctrl_reg; uint8_t state_reg; int int_pin; uint8_t wait_reg; uint8_t int_reg; #ifdef CONFIG_HAS_EARLYSUSPEND //struct early_suspend stk_early_suspend; #endif uint16_t ps_thd_h; uint16_t ps_thd_l; #ifdef CALI_PS_EVERY_TIME uint16_t ps_high_thd_boot; uint16_t ps_low_thd_boot; #endif struct mutex io_lock; struct input_dev *ps_input_dev; int32_t ps_distance_last; bool ps_enabled; bool re_enable_ps; struct wake_lock ps_wakelock; #ifdef STK_POLL_PS struct hrtimer ps_timer; struct work_struct stk_ps_work; struct workqueue_struct *stk_ps_wq; struct wake_lock ps_nosuspend_wl; #endif struct input_dev *als_input_dev; int32_t als_lux_last; uint32_t als_transmittance; bool als_enabled; bool re_enable_als; ktime_t ps_poll_delay; ktime_t als_poll_delay; #ifdef STK_POLL_ALS struct work_struct stk_als_work; struct hrtimer als_timer; struct workqueue_struct *stk_als_wq; #endif bool first_boot; #ifdef STK_TUNE0 uint16_t psa; uint16_t psi; uint16_t psi_set; struct hrtimer ps_tune0_timer; struct workqueue_struct *stk_ps_tune0_wq; struct work_struct stk_ps_tune0_work; ktime_t ps_tune0_delay; bool tune_zero_init_proc; uint32_t ps_stat_data[3]; int data_count; int stk_max_min_diff; int stk_lt_n_ct; int stk_ht_n_ct; #endif #ifdef STK_ALS_FIR struct data_filter fir; atomic_t firlength; #endif atomic_t recv_reg; #ifdef STK_GES struct input_dev *ges_input_dev; int ges_enabled; int re_enable_ges; atomic_t gesture2; #endif #ifdef STK_IRS int als_data_index; #endif #ifdef STK_QUALCOMM_POWER_CTRL struct regulator *vdd; struct regulator *vio; bool power_enabled; #endif uint8_t pid; uint8_t p_wv_r_bd_with_co; uint32_t als_code_last; }; static struct stk3x1x_data *ps_data; const int ALS_LEVEL[] = {100, 1600, 2250, 3200, 6400, 12800, 26000}; static void set_stk_power(bool flag) { struct regulator *ldo=NULL; int ret; ldo = regulator_get(NULL, "rk818_ldo2"); if(ldo==NULL){ printk("set_stk_sensor_power ldo is nulln"); return; } if(flag){ regulator_set_voltage(ldo, 3300000, 3300000); ret = regulator_enable(ldo); if(ret < 0){ printk("----->%s:enable error...n",__func__); } regulator_put(ldo); }else{ regulator_disable(ldo); regulator_put(ldo); } } static struct stk3x1x_platform_data stk3x1x_pfdata={ .state_reg = 0x0, /* disable all */ .psctrl_reg = 0x31, /* ps_persistance=1, ps_gain=64X, PS_IT=0.391ms */ .alsctrl_reg = 0x39, /* als_persistance=1, als_gain=64X, ALS_IT=100ms */ .ledctrl_reg = 0xFF, /* 100mA IRDR, 64/64 LED duty */ .wait_reg = 0x07, /* 50 ms */ .ps_thd_h = 800, .ps_thd_l = 600, //.int_pin = sprd_3rdparty_gpio_pls_irq, .transmittance = 500, .stk_max_min_diff = 200, .stk_lt_n_ct = 60, .stk_ht_n_ct = 80, }; /*****************************************************************************/ #ifndef STK_POLL_ALS static int32_t stk3x1x_set_als_thd_l(struct i2c_client *client, uint16_t thd_l) { unsigned char val[3]; int ret; val[0] = STK_THDL1_ALS_REG; val[1] = (thd_l & 0xFF00) >> 8; val[2] = thd_l & 0x00FF; ret = sensor_tx_data(client, val, 3); // ret = sensor_write_reg(client, STK_THDL1_ALS_REG, ); // if(ret) // printk("%s:fail to active sensorn",__func__); return ret; } static int32_t stk3x1x_set_als_thd_h(struct i2c_client *client, uint16_t thd_h) { unsigned char val[2]; int ret; val[0] = STK_THDH1_ALS_REG; val[1] = (thd_h & 0xFF00) >> 8; val[2] = thd_h & 0x00FF; ret = sensor_tx_data(client, val, 3); // ret = sensor_write_reg(client, STK_THDL1_ALS_REG, ); // if(ret) // printk("%s:fail to active sensorn",__func__); return ret; } #endif static int light_sensor_active(struct i2c_client *client, int enable, int rate) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; // int status = 0; // char buffer[3] = {0}; // int high = 0x80, low = 0x60; #ifdef STK_IRS int ret = 0; #endif sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); #ifndef STK_POLL_ALS if (enable) { stk3x1x_set_als_thd_h(client, 0x0000); stk3x1x_set_als_thd_l(client, 0xFFFF); } #ifdef STK_IRS if(enable && !(sensor->ops->ctrl_data & STK_STATE_EN_PS_MASK)) { ret = stk3x1x_get_ir_reading(ps_data, STK_IRS_IT_REDUCE); if(ret > 0) ps_data->ir_code = ret; } #endif #endif sensor->ops->ctrl_data = (uint8_t)((sensor->ops->ctrl_data) & (~(STK_STATE_EN_ALS_MASK | STK_STATE_EN_WAIT_MASK))); if(enable) sensor->ops->ctrl_data |= STK_STATE_EN_ALS_MASK; else if (sensor->ops->ctrl_data & STK_STATE_EN_PS_MASK) sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK; printk("%s:reg=0x%x,reg_ctrl=0x%x,enable=%dn",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); if(result) printk("%s:fail to active sensorn",__func__); if(enable) { #ifdef STK_IRS ps_data->als_data_index = 0; #endif // sensor->ops->report(sensor->client); } ps_data->als_enabled = enable?true:false; return result; } static int32_t stk3x1x_check_pid(struct i2c_client *client) { char value[2] = {0}, pid_msb; int result; ps_data->p_wv_r_bd_with_co = 0; value[0] = STK_PDT_ID_REG; result = sensor_rx_data(client, value, 2); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } printk(KERN_INFO "%s: PID=0x%x, RID=0x%xn", __func__, value[0], value[1]); ps_data->pid = value[0]; if(value[0] == STK3311WV_PID) ps_data->p_wv_r_bd_with_co |= 0b100; if(value[1] == 0xC3) ps_data->p_wv_r_bd_with_co |= 0b010; // if(stk3x1x_read_otp25(ps_data) == 1) // { // ps_data->p_wv_r_bd_with_co |= 0b001; // } printk(KERN_INFO "%s: p_wv_r_bd_with_co = 0x%xn", __func__, ps_data->p_wv_r_bd_with_co); pid_msb = value[0] & 0xF0; switch(pid_msb) { case 0x10: case 0x20: case 0x30: return 0; default: printk(KERN_ERR "%s: invalid PID(%#x)n", __func__, value[0]); return -1; } return 0; } static int light_sensor_init(struct i2c_client *client) { int res = 0; printk("stk %s init ...n", __func__); set_stk_power(1); ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL); if(!ps_data) { printk(KERN_ERR "%s: failed to allocate stk3x1x_datan", __func__); return -ENOMEM; } res = sensor_write_reg(client, STK_WAIT_REG, 0x7F); if(res < 0){ printk("stk %s i2c test error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_read_reg(client, STK_WAIT_REG); if(res != 0x7F) { printk("stk %s i2c test error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_SW_RESET_REG, 0x0); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } //usleep_range(13000, 15000); res = stk3x1x_check_pid(client); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_STATE_REG, stk3x1x_pfdata.state_reg); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_PSCTRL_REG, stk3x1x_pfdata.psctrl_reg); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } if(ps_data->pid == STK3310SA_PID || ps_data->pid == STK3311SA_PID) stk3x1x_pfdata.ledctrl_reg &= 0x3F; res = sensor_write_reg(client, STK_LEDCTRL_REG, stk3x1x_pfdata.ledctrl_reg); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_WAIT_REG, stk3x1x_pfdata.wait_reg); if(res < 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } #ifndef STK_POLL_ALS value = STK_INT_REG; res = sensor_rx_data(client, value, 1); if(res){ printk("%s:line=%d,error=%dn",__func__,__LINE__, res); return res; } value |= STK_INT_ALS; res = sensor_write_reg(client, STK_INT_REG, value); if(res <= 0){ printk("stk %s i2c error line:%dn", __func__,__LINE__); goto EXIT_ERR; } #endif ps_data->als_code_last = 0; printk("stk %s init successful n", __func__); return 0; EXIT_ERR: printk(KERN_ERR "stk init fail dev: %dn", res); return res; } static int light_report_abs_value(struct input_dev *input, int data) { unsigned char index = 0; if(data <= ALS_LEVEL[0]){ index = 0;goto report; } else if(data <= ALS_LEVEL[1]){ index = 1;goto report; } else if(data <= ALS_LEVEL[2]){ index = 2;goto report; } else if(data <= ALS_LEVEL[3]){ index = 3;goto report; } else if(data <= ALS_LEVEL[4]){ index = 4;goto report; } else if(data <= ALS_LEVEL[5]){ index = 5;goto report; } else if(data <= ALS_LEVEL[6]){ index = 6;goto report; } else{ index = 7;goto report; } report: input_report_abs(input, ABS_MISC, index); input_sync(input); return index; } /* static int stk_allreg(struct i2c_client *client) { uint8_t ps_reg[0x22]; int cnt = 0; for(cnt=0;cnt<0x20;cnt++) { ps_reg[cnt] = sensor_read_reg(client, cnt); if(ps_reg[cnt] < 0) { printk("%s fail n", __func__); return -EINVAL; } printk(KERN_INFO "reg[0x%2X]=0x%2Xn", cnt, ps_reg[cnt]); } return 0; } */ static int32_t stk3x1x_set_irs_it_slp(struct i2c_client *client, uint16_t *slp_time, int32_t ials_it_reduce) { int irs_alsctrl; int32_t ret; irs_alsctrl = (stk3x1x_pfdata.alsctrl_reg & 0x0F) - ials_it_reduce; switch(irs_alsctrl) { case 2: *slp_time = 1; break; case 3: *slp_time = 2; break; case 4: *slp_time = 3; break; case 5: *slp_time = 6; break; case 6: *slp_time = 12; break; case 7: *slp_time = 24; break; case 8: *slp_time = 48; break; case 9: *slp_time = 96; break; case 10: *slp_time = 192; break; default: printk(KERN_ERR "%s: unknown ALS IT=0x%xn", __func__, irs_alsctrl); ret = -EINVAL; return ret; } irs_alsctrl |= (stk3x1x_pfdata.alsctrl_reg & 0xF0); ret = sensor_write_reg(client, STK_ALSCTRL_REG, irs_alsctrl); if(ret <= 0) return ret; return 0; } static int stk3x1x_get_ir_reading(struct i2c_client *client, int32_t als_it_reduce) { int res = 0; int32_t word_data, ret; int w_reg, retry = 0; uint16_t irs_slp_time = 100; char buffer[2] = {0}; ret = stk3x1x_set_irs_it_slp(client, &irs_slp_time, als_it_reduce); if(ret < 0) return ret; w_reg = sensor_read_reg(client, STK_STATE_REG); if(w_reg <= 0) { printk("stk %s i2c error(%d)n", __func__, w_reg); return ret; } w_reg |= STK_STATE_EN_IRS_MASK; res = sensor_write_reg(client, STK_STATE_REG, w_reg); if(res <= 0) return res; msleep(irs_slp_time); do { usleep_range(3000, 4000); w_reg = sensor_read_reg(client, STK_FLAG_REG); if(w_reg <= 0) return w_reg; retry++; }while(retry < 10 && ((w_reg & STK_FLG_IR_RDY_MASK) == 0)); if(retry == 10) { printk(KERN_ERR "%s: ir data is not ready for a long timen", __func__); return -EINVAL; } w_reg &= (~STK_FLG_IR_RDY_MASK); res = sensor_write_reg(client, STK_FLAG_REG, w_reg); if(res <= 0) return res; buffer[0] = STK_DATA1_IR_REG; res = sensor_rx_data(client, buffer, 2); if(res) { printk("%s:line=%d,errorn",__func__,__LINE__); return res; } word_data = ((buffer[0]<<8) | buffer[1]); printk(KERN_INFO "%s: ir=%dn", __func__, word_data); res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg); if(res <= 0) return res; return word_data; } #ifdef STK_IRS static int stk_als_ir_skip_als(struct i2c_client *client, struct sensor_private_data *sensor) { int ret; unsigned char buffer[2] = {0}; if(ps_data->als_data_index < 60000) ps_data->als_data_index++; else ps_data->als_data_index = 0; if( ps_data->als_data_index % 10 == 1) { buffer[0] = STK_DATA1_ALS_REG; ret = sensor_rx_data(client, buffer, 2); if(ret) { printk("%s:line=%d,error=%dn",__func__,__LINE__, ret); return ret; } return 1; } return 0; } #endif static int stk_als_cal(struct i2c_client *client, int *als_data) { int32_t ir_data = 0; #ifdef STK_ALS_FIR int index; int firlen = atomic_read(&ps_data->firlength); #endif #ifdef STK_IRS const int ir_enlarge = 1 << (STK_ALS_READ_IRS_IT_REDUCE - STK_IRS_IT_REDUCE); #endif if(ps_data->p_wv_r_bd_with_co & 0b010) { if(*als_data < STK_ALS_THRESHOLD && ps_data->als_code_last > 10000) { ir_data = stk3x1x_get_ir_reading(client, STK_ALS_READ_IRS_IT_REDUCE); #ifdef STK_IRS if(ir_data > 0) ps_data->ir_code = ir_data * ir_enlarge; #endif // printk(KERN_INFO "%s: *als_data=%d, als_code_last=%d,ir_data=%dn", // __func__, *als_data, ps_data->als_code_last, ir_data); if(ir_data > (STK_ALS_THRESHOLD*3)) { *als_data = ps_data->als_code_last; } } #ifdef STK_IRS else { ps_data->ir_code = 0; } #endif } ps_data->als_code_last = *als_data; #ifdef STK_ALS_FIR if(ps_data->fir.number < firlen) { ps_data->fir.raw[ps_data->fir.number] = *als_data; ps_data->fir.sum += *als_data; ps_data->fir.number++; ps_data->fir.idx++; } else { index = ps_data->fir.idx % firlen; ps_data->fir.sum -= ps_data->fir.raw[index]; ps_data->fir.raw[index] = *als_data; ps_data->fir.sum += *als_data; ps_data->fir.idx++; *als_data = ps_data->fir.sum/firlen; } #endif return 0; } #ifdef STK_IRS static void stk_als_ir_get_corr(int32_t als) { int32_t als_comperator; if(ps_data->ir_code) { ps_data->als_correct_factor = 1000; if(als < STK_IRC_MAX_ALS_CODE && als > STK_IRC_MIN_ALS_CODE && ps_data->ir_code > STK_IRC_MIN_IR_CODE) { als_comperator = als * STK_IRC_ALS_NUMERA / STK_IRC_ALS_DENOMI; if(ps_data->ir_code > als_comperator) ps_data->als_correct_factor = STK_IRC_ALS_CORREC; } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: als=%d, ir=%d, als_correct_factor=%d", __func__, als, ps_data->ir_code, ps_data->als_correct_factor); #endif ps_data->ir_code = 0; } return; } static int stk_als_ir_run(struct i2c_client *client) { int ret; if(ps_data->als_data_index % 10 == 0) { if(ps_data->ps_distance_last != 0 && ps_data->ir_code == 0) { ret = stk3x1x_get_ir_reading(client, STK_IRS_IT_REDUCE); if(ret > 0) ps_data->ir_code = ret; } return ret; } return 0; } #endif static int light_sensor_report_value(struct i2c_client *client) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; uint32_t value = 0; unsigned char buffer[2] = {0}; char index = 0; if(sensor->ops->read_len < 2) //sensor->ops->read_len = 1 { printk("%s:lenth is error,len=%dn",__func__,sensor->ops->read_len); return -1; } value = sensor_read_reg(client, STK_FLAG_REG); if(value < 0) { printk("stk %s read STK_FLAG_REG, ret=%dn", __func__, value); return value; } if(!(value & STK_FLG_ALSDR_MASK)) return 0; #ifdef STK_IRS result = stk_als_ir_skip_als(client, sensor); if(result == 1) return 0; #endif buffer[0] = sensor->ops->read_reg; result = sensor_rx_data(client, buffer, sensor->ops->read_len); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } value = (buffer[0] << 8) | buffer[1]; #ifdef STK_DEBUG_PRINTF printk("%s: value == %d n",__func__,value); #endif stk_als_cal(client, &value); #ifdef STK_IRS stk_als_ir_get_corr(value); value = value * ps_data->als_correct_factor / 1000; #endif index = light_report_abs_value(sensor->input_dev, value); /* if(sensor->pdata->irq_enable) { if(sensor->ops->int_status_reg) { value = sensor_read_reg(client, sensor->ops->int_status_reg); } if(value & STA_PS_INT) { value &= ~STA_PS_INT; result = sensor_write_reg(client, sensor->ops->int_status_reg,value); //clear int if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } } } */ #ifdef STK_IRS stk_als_ir_run(client); #endif return result; } struct sensor_operate light_stk3x1x_ops = { .name = "ls_stk3x1x", .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct .id_i2c = LIGHT_ID_STK3X1X, //i2c id number .read_reg = STK_DATA1_ALS_REG, //read data .read_len = 2, //data length .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register .id_data = SENSOR_UNKNOW_DATA, //device id .precision = 16, //16 bits .ctrl_reg = STK_STATE_REG, //enable or disable .int_status_reg = SENSOR_UNKNOW_DATA, //intterupt status register .range = {100,65535}, //range .brightness ={10,255}, //brightness .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, .active = light_sensor_active, .init = light_sensor_init, .report = light_sensor_report_value, }; static int light_stk3x1x_probe(struct i2c_client *client, const struct i2c_device_id *devid) { return sensor_register_device(client, NULL, devid, &light_stk3x1x_ops); } static int light_stk3x1x_remove(struct i2c_client *client) { return sensor_unregister_device(client, NULL, &light_stk3x1x_ops); } static const struct i2c_device_id light_stk3x1x_id[] = { {"ls_stk3x1x", LIGHT_ID_STK3X1X}, {} }; static struct i2c_driver light_stk3x1x_driver = { .probe = light_stk3x1x_probe, .remove = light_stk3x1x_remove, .shutdown = sensor_shutdown, .id_table = light_stk3x1x_id, .driver = { .name = "light_stk3x1x", #ifdef CONFIG_PM .pm = &sensor_pm_ops, #endif }, }; module_i2c_driver(light_stk3x1x_driver); MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sensortek.com.tw>"); MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION);
二、距离传感驱动代码 kerneldriversinputsensorspsensorps_stk3x1x.c,代码里面带sensor->pdata->irq_enable部分的是我自己添加来根据dts里面的配置irq_enable来处理中断的模式,默认是轮询模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959/* * ps_stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x * proximity/ambient light sensor * * Copyright (C) 2012~2015 Lex Hsieh / sensortek <lex_hsieh@sensortek.com.tw> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/input.h> #include <linux/workqueue.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/errno.h> #include <linux/wakelock.h> #include <linux/interrupt.h> #include <linux/gpio.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/sensor-dev.h> #include <linux/of_gpio.h> #ifdef CONFIG_HAS_EARLYSUSPEND //#include <linux/earlysuspend.h> #endif #define DRIVER_VERSION "3.10.0_0429" //#define STK_POLL_PS #define STK_TUNE0 #define STK_DEBUG_PRINTF #include "linux/stk3x1x.h" /* Define Register Map */ #define STK_STATE_REG 0x00 #define STK_PSCTRL_REG 0x01 #define STK_ALSCTRL_REG 0x02 #define STK_LEDCTRL_REG 0x03 #define STK_INT_REG 0x04 #define STK_WAIT_REG 0x05 #define STK_THDH1_PS_REG 0x06 #define STK_THDH2_PS_REG 0x07 #define STK_THDL1_PS_REG 0x08 #define STK_THDL2_PS_REG 0x09 #define STK_THDH1_ALS_REG 0x0A #define STK_THDH2_ALS_REG 0x0B #define STK_THDL1_ALS_REG 0x0C #define STK_THDL2_ALS_REG 0x0D #define STK_FLAG_REG 0x10 #define STK_DATA1_PS_REG 0x11 #define STK_DATA2_PS_REG 0x12 #define STK_DATA1_ALS_REG 0x13 #define STK_DATA2_ALS_REG 0x14 #define STK_DATA1_OFFSET_REG 0x15 #define STK_DATA2_OFFSET_REG 0x16 #define STK_DATA1_IR_REG 0x17 #define STK_DATA2_IR_REG 0x18 #define STK_PDT_ID_REG 0x3E #define STK_RSRVD_REG 0x3F #define STK_SW_RESET_REG 0x80 #define STK_STATE_EN_IRS_MASK 0x80 #define STK_STATE_EN_AK_MASK 0x40 #define STK_STATE_EN_ASO_MASK 0x20 #define STK_STATE_EN_IRO_MASK 0x10 #define STK_STATE_EN_WAIT_MASK 0x04 #define STK_STATE_EN_ALS_MASK 0x02 #define STK_STATE_EN_PS_MASK 0x01 #define STK_FLG_ALSDR_MASK 0x80 #define STK_FLG_PSDR_MASK 0x40 #define STK_FLG_ALSINT_MASK 0x20 #define STK_FLG_PSINT_MASK 0x10 #define STK_FLG_OUI_MASK 0x04 #define STK_FLG_IR_RDY_MASK 0x02 #define STK_FLG_NF_MASK 0x01 #define STK_INT_ALS 0x08 /*****************************************************************************/ #define STK_MAX_MIN_DIFF 200 #define STK_LT_N_CT 100 #define STK_HT_N_CT 150 /*****************************************************************************/ #define STK3310SA_PID 0x17 #define STK3311SA_PID 0x1E #define STK3311WV_PID 0x1D /*****************************************************************************/ /* INT 0x04 */ #define PS_INT_DISABLE 0xF8 #define PS_INT_ENABLE (1 << 0) #define PS_INT_ENABLE_FLGNFH (2 << 0) #define PS_INT_ENABLE_FLGNFL (3 << 0) #define PS_INT_MODE_ENABLE (4 << 0) #define PS_INT_ENABLE_THL (5 << 0) #define PS_INT_ENABLE_THH (6 << 0) #define PS_INT_ENABLE_THHL (7 << 0) #define ALS_INT_DISABLE (0 << 3) #define ALS_INT_ENABLE (1 << 3) #define INT_CTRL_PS_OR_LS (0 << 7) #define INT_CTRL_PS_AND_LS (1 << 7) /* FLAG 0x10 */ /* FLAG 0x10 */ #define STK_FLAG_NF (1 << 0) #define STK_FLAG_IR_RDY (1 << 1) #define STK_FLAG_OUI (1 << 2) #define STK_FLAG_PSINT (1 << 4) #define STK_FLAG_ALSINT (1 << 5) #define STK_FLAG_PSDR (1 << 6) #define STK_FLAG_ALSDR (1 << 7) #ifdef STK_ALS_FIR #define STK_FIR_LEN 8 #define MAX_FIR_LEN 32 struct data_filter { u16 raw[MAX_FIR_LEN]; int sum; int number; int idx; }; #endif struct stk3x1x_data { int int_pin; uint16_t ps_thd_h; uint16_t ps_thd_l; #ifdef CALI_PS_EVERY_TIME uint16_t ps_high_thd_boot; uint16_t ps_low_thd_boot; #endif int32_t ps_distance_last; bool ps_enabled; // bool re_enable_ps; bool first_boot; #ifdef STK_TUNE0 uint16_t psa; uint16_t psi; uint16_t psi_set; struct hrtimer ps_tune0_timer; struct workqueue_struct *stk_ps_tune0_wq; struct work_struct stk_ps_tune0_work; ktime_t ps_tune0_delay; bool tune_zero_init_proc; uint32_t ps_stat_data[3]; int data_count; int stk_max_min_diff; int stk_lt_n_ct; int stk_ht_n_ct; #endif atomic_t recv_reg; uint8_t pid; uint8_t p_wv_r_bd_with_co; }; struct stk3x1x_data *ps_data; /*****************************************************************************/ static struct stk3x1x_platform_data stk3x1x_pfdata={ .state_reg = 0x0, /* disable all */ .psctrl_reg = 0x31, /* ps_persistance=1, ps_gain=64X, PS_IT=0.391ms */ .alsctrl_reg = 0x39, /* als_persistance=1, als_gain=64X, ALS_IT=100ms */ .ledctrl_reg = 0xFF, /* 100mA IRDR, 64/64 LED duty */ .wait_reg = 0x07, /* 50 ms */ .ps_thd_h = 1700, .ps_thd_l = 1500, //.int_pin = sprd_3rdparty_gpio_pls_irq, .transmittance = 500, #if defined(CONFIG_SOFIA_3GR_BND_I706) .stk_max_min_diff = 15, .stk_lt_n_ct = 50, .stk_ht_n_ct = 75, #else .stk_max_min_diff = 10, .stk_lt_n_ct = 45, .stk_ht_n_ct = 60, #endif }; static int32_t stk3x1x_check_pid(struct i2c_client *client); static int stk_ps_tune_zero_init(struct i2c_client *client); /*****************************************************************************/ static int32_t stk3x1x_set_ps_thd_h(struct i2c_client *client, uint16_t thd_h) { unsigned char val[2]; int ret; val[0] = (thd_h & 0xFF00) >> 8; val[1] = thd_h & 0x00FF; ret = sensor_write_reg(client, STK_THDH1_PS_REG, val[0]); if(ret < 0){ printk("%s: fail, ret=%dn", __func__, ret); } ret = sensor_write_reg(client, STK_THDH2_PS_REG, val[1]); if(ret < 0){ printk("%s: fail, ret=%dn", __func__, ret); } return ret; } static int32_t stk3x1x_set_ps_thd_l(struct i2c_client *client, uint16_t thd_l) { unsigned char val[2]; int ret; val[0] = (thd_l & 0xFF00) >> 8; val[1] = thd_l & 0x00FF; ret = sensor_write_reg(client, STK_THDL1_PS_REG, val[0]); if(ret < 0){ printk("%s: fail, ret=%dn", __func__, ret); } ret = sensor_write_reg(client, STK_THDL2_PS_REG, val[1]); if(ret < 0){ printk("%s: fail, ret=%dn", __func__, ret); } return ret; } /* static uint32_t stk3x1x_get_ps_reading(struct i2c_client *client, u16 *data) { unsigned char value[2]; int err = 0; value[0] = sensor_read_reg(client, STK_DATA1_PS_REG); if(value[0] < 0){ goto EXIT_ERR; } value[1] = sensor_read_reg(client, STK_DATA2_PS_REG); if(value[1] < 0){ goto EXIT_ERR; } *data = ((value[0]<<8) | value[1]); return 0; EXIT_ERR: printk("stk3x1x_read_ps failn"); return err; } */ static int proximity_sensor_active(struct i2c_client *client, int enable, int rate) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; // u16 ps_code; #ifdef STK_DEBUG_PRINTF printk("%s init proc = %dn", __func__, (ps_data->tune_zero_init_proc ? 1 : 0)); #endif sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); sensor->ops->ctrl_data &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK); if(enable) { sensor->ops->ctrl_data |= STK_STATE_EN_PS_MASK; if(!(sensor->ops->ctrl_data & STK_STATE_EN_ALS_MASK)) sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK; } #ifdef STK_DEBUG_PRINTF printk("%s:reg=0x%x,reg_ctrl=0x%x,enable=%dn",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); #endif result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); if(result) printk("%s:fail to active sensorn",__func__); if(enable) { usleep_range(4000, 5000); sensor->ops->report(sensor->client); // stk3x1x_get_ps_reading(client, &ps_code); // stk3x1x_set_ps_thd_h(client, ps_code + STK_HT_N_CT); // stk3x1x_set_ps_thd_l(client, ps_code + STK_LT_N_CT); #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: thdh:%d, thdl:%dn", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); #endif stk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h); stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l); } ps_data->ps_enabled = enable?true:false; ps_data->ps_distance_last = 1; ps_data->psa = 0x0; ps_data->psi = 0xFFFF; ps_data->psi_set = 0; ps_data->stk_max_min_diff = stk3x1x_pfdata.stk_max_min_diff; ps_data->stk_lt_n_ct = stk3x1x_pfdata.stk_lt_n_ct; ps_data->stk_ht_n_ct = stk3x1x_pfdata.stk_ht_n_ct; #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: lt:%d ht:%d max diff:%dn", __func__, ps_data->stk_lt_n_ct, ps_data->stk_ht_n_ct, ps_data->stk_max_min_diff); #endif return result; } static int32_t stk3x1x_check_pid(struct i2c_client *client) { char value[2] = {0}, pid_msb; int result; ps_data->p_wv_r_bd_with_co = 0; value[0] = STK_PDT_ID_REG; result = sensor_rx_data(client, value, 2); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: PID=0x%x, RID=0x%xn", __func__, value[0], value[1]); #endif ps_data->pid = value[0]; if(value[0] == STK3311WV_PID) ps_data->p_wv_r_bd_with_co |= 0b100; if(value[1] == 0xC3) ps_data->p_wv_r_bd_with_co |= 0b010; // if(stk3x1x_read_otp25(ps_data) == 1) // { // ps_data->p_wv_r_bd_with_co |= 0b001; // } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: p_wv_r_bd_with_co = 0x%xn", __func__, ps_data->p_wv_r_bd_with_co); #endif pid_msb = value[0] & 0xF0; switch(pid_msb) { case 0x10: case 0x20: case 0x30: return 0; default: printk(KERN_ERR "%s: invalid PID(%#x)n", __func__, value[0]); return -1; } return 0; } /* static int stk_allreg(struct i2c_client *client) { uint8_t ps_reg[0x22]; int cnt = 0; for(cnt=0;cnt<0x20;cnt++) { ps_reg[cnt] = sensor_read_reg(client, cnt); if(ps_reg[cnt] < 0) { printk("%s fail n", __func__); return -EINVAL; } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "reg[0x%2X]=0x%2Xn", cnt, ps_reg[cnt]); #endif } return 0; } */ #ifdef STK_TUNE0 static int stk_ps_val(struct i2c_client *client) { int mode; int32_t word_data, lii; unsigned char value[4]; int ret; value[0] = 0x20; ret = sensor_rx_data(client, value, 4); if(ret) { printk("%s:line=%d,error=%dn",__func__,__LINE__, ret); return ret; } word_data = (value[0]<<8) | value[1]; word_data += ((value[2]<<8) | value[3]); mode = (stk3x1x_pfdata.psctrl_reg) & 0x3F; if(mode == 0x30) lii = 100; else if (mode == 0x31) lii = 200; else if (mode == 0x32) lii = 400; else if (mode == 0x33) lii = 800; else { printk(KERN_ERR "%s: unsupported PS_IT(0x%x)n", __func__, mode); return -1; } if(word_data > lii) { printk(KERN_INFO "%s: word_data=%d, lii=%dn", __func__, word_data, lii); return 0xFFFF; } return 0; } static int stk_ps_tune_zero_final(struct i2c_client *client) { int ret; int value; value = 0; #ifndef STK_POLL_PS value |= 0x01; #endif #ifndef STK_POLL_ALS value |= STK_INT_ALS; #endif ret = sensor_write_reg(client, STK_INT_REG, value); if(ret <= 0) return ret; value = sensor_read_reg(client, STK_STATE_REG); if(!(value & STK_STATE_EN_ALS_MASK)) value |= STK_STATE_EN_WAIT_MASK; if(ps_data->ps_enabled) value |= STK_STATE_EN_PS_MASK; ret = sensor_write_reg(client, STK_STATE_REG, value); if (ret < 0) { printk(KERN_ERR "%s: write i2c errorn", __func__); return ret; } if(ps_data->data_count == -1) { printk(KERN_INFO "%s: exceed limitn", __func__); ps_data->tune_zero_init_proc = false; return 0; } ps_data->psa = ps_data->ps_stat_data[0]; ps_data->psi = ps_data->ps_stat_data[2]; ps_data->ps_thd_h = ps_data->ps_stat_data[1] + ps_data->stk_ht_n_ct; ps_data->ps_thd_l = ps_data->ps_stat_data[1] + ps_data->stk_lt_n_ct; stk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h); stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l); #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "stk %s: set HT=%d,LT=%dn", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); #endif ps_data->tune_zero_init_proc = false; return 0; } static int32_t stk_tune_zero_get_ps_data(struct i2c_client *client, int ps_adc) { int ret; ret = stk_ps_val(client); if(ret == 0xFFFF) { ps_data->data_count = -1; stk_ps_tune_zero_final(client); return 0; } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: ps_adc #%d=%dn", __func__, ps_data->data_count, ps_adc); #endif ps_data->ps_stat_data[1] += ps_adc; if(ps_adc > ps_data->ps_stat_data[0]) ps_data->ps_stat_data[0] = ps_adc; if(ps_adc < ps_data->ps_stat_data[2]) ps_data->ps_stat_data[2] = ps_adc; ps_data->data_count++; if(ps_data->data_count == 5) { ps_data->ps_stat_data[1] /= ps_data->data_count; stk_ps_tune_zero_final(client); } return 0; } static int stk_ps_tune_zero_init(struct i2c_client *client) { //struct sensor_private_data *sensor = // (struct sensor_private_data *) i2c_get_clientdata(client); ps_data->psa = 0x0; ps_data->psi = 0xFFFF; ps_data->psi_set = 0; ps_data->ps_stat_data[0] = 0; ps_data->ps_stat_data[2] = 9999; ps_data->ps_stat_data[1] = 0; ps_data->data_count = 0; ps_data->tune_zero_init_proc = false; /* sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); sensor->ops->ctrl_data &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK); sensor->ops->ctrl_data |= STK_STATE_EN_PS_MASK; if(!(sensor->ops->ctrl_data & STK_STATE_EN_ALS_MASK)) sensor->ops->ctrl_data |= STK_STATE_EN_WAIT_MASK; result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); if(result) printk("%s:fail to active sensorn",__func__); #ifdef STK_DEBUG_PRINTF printk("%s:reg=0x%x,reg_ctrl=0x%xn",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data); #endif result = sensor_write_reg(client, STK_INT_REG, 0); if(result) printk("%s:fail to active sensorn",__func__); */ return 0; } static int stk_ps_tune_zero_func_fae(struct i2c_client *client, int word_data) { int ret, diff; #ifdef STK_DEBUG_PRINTF //int cnt = 0; //int ps_reg[0x22]; #endif if(ps_data->psi_set || !(ps_data->ps_enabled)) return 0; ret = stk_ps_val(client); if(ret == 0) { if(word_data == 0) { //printk(KERN_ERR "%s: incorrect word data (0)n", __func__); return 0xFFFF; } if(word_data > ps_data->psa) { ps_data->psa = word_data; #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: update psa: psa=%d,psi=%dn", __func__, ps_data->psa, ps_data->psi); #endif } if(word_data < ps_data->psi) { ps_data->psi = word_data; #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: update psi: psa=%d,psi=%dn", __func__, ps_data->psa, ps_data->psi); #endif } } diff = ps_data->psa - ps_data->psi; #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: diff:%d psa:%d, psi:%d max diff:%dn", __func__, diff, ps_data->psa, ps_data->psi, ps_data->stk_max_min_diff); #endif if(diff > ps_data->stk_max_min_diff) { ps_data->psi_set = ps_data->psi; ps_data->ps_thd_h = ps_data->psi + ps_data->stk_ht_n_ct; ps_data->ps_thd_l = ps_data->psi + ps_data->stk_lt_n_ct; #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: tune0 thd_h:%d thd_l:%dn", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); #endif #if 0 //def STK_DEBUG_PRINTF cnt = 0x6; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x7; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x8; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x9; ps_reg[cnt] = sensor_read_reg(client, cnt); printk(KERN_INFO "%s: befor [0x06/0x07]%d, %d [0x08/0x09]%d, %d n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]); #endif stk3x1x_set_ps_thd_h(client, ps_data->ps_thd_h); stk3x1x_set_ps_thd_l(client, ps_data->ps_thd_l); #if 0 //def STK_DEBUG_PRINTF cnt = 0x6; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x7; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x8; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x9; ps_reg[cnt] = sensor_read_reg(client, cnt); printk(KERN_INFO "%s: after [0x06/0x07]%d, %d [0x08/0x09]%d, %d n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]); #endif #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: FAE tune0 found thd_h:%d thd_l:%dn", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); #endif } return 0; } #endif static int stk_ps_report(struct i2c_client *client, int ps) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; char buffer[2] = {0}; int reg_flag = 0; #if 0 //def STK_DEBUG_PRINTF int cnt = 0; int ps_reg[0x22]; #endif buffer[0] = STK_FLAG_REG; result = sensor_rx_data(client, buffer, 1); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } reg_flag = buffer[0]; reg_flag = (reg_flag & 0x1); ps_data->ps_distance_last = reg_flag ? 1:0; #if 0 //def STK_DEBUG_PRINTF cnt = 0x6; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x7; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x8; ps_reg[cnt] = sensor_read_reg(client, cnt); cnt = 0x9; ps_reg[cnt] = sensor_read_reg(client, cnt); printk(KERN_INFO "%s: [0x06/0x07]%d, %d [0x08/0x09]%d, %d n", __func__, ps_reg[0x6], ps_reg[0x7], ps_reg[0x8], ps_reg[0x9]); #endif if(ps > ps_data->ps_thd_h){ ps_data->ps_distance_last = 0; }else if(ps < ps_data->ps_thd_l){ ps_data->ps_distance_last = 1; } input_report_abs(sensor->input_dev, ABS_DISTANCE, ps_data->ps_distance_last); input_sync(sensor->input_dev); #ifdef STK_DEBUG_PRINTF printk("%s:ps=0x%x,flag=%d, dis=%dn",__func__, ps,reg_flag, ps_data->ps_distance_last); #endif return 0; } static int proximity_sensor_init(struct i2c_client *client) { struct sensor_private_data *sensor = (struct sensor_private_data *)i2c_get_clientdata(client); int res = 0; char value; int val = 0; printk("stk %s init ...n", __func__); ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL); if(!ps_data) { printk(KERN_ERR "%s: failed to allocate stk3x1x_datan", __func__); return -ENOMEM; } res = sensor_write_reg(client, STK_WAIT_REG, 0x7F); if(res < 0){ printk("stk %s int error 1n", __func__); goto EXIT_ERR; } value = sensor_read_reg(client, STK_WAIT_REG); if(value != 0x7F) { printk("stk %s i2c test errorn", __func__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_SW_RESET_REG, 0x0); if(res < 0){ printk("stk %s int error 2n", __func__); goto EXIT_ERR; } //usleep_range(13000, 15000); res = stk3x1x_check_pid(client); if(res < 0){ printk("stk %s int error 3n", __func__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_STATE_REG, stk3x1x_pfdata.state_reg); if(res < 0){ printk("stk %s int error 4n", __func__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_PSCTRL_REG, stk3x1x_pfdata.psctrl_reg); if(res < 0){ printk("stk %s int error 5n", __func__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_ALSCTRL_REG, stk3x1x_pfdata.alsctrl_reg); if(res < 0){ printk("stk %s int error 6n", __func__); goto EXIT_ERR; } if(ps_data->pid == STK3310SA_PID || ps_data->pid == STK3311SA_PID) stk3x1x_pfdata.ledctrl_reg &= 0x3F; res = sensor_write_reg(client, STK_LEDCTRL_REG, stk3x1x_pfdata.ledctrl_reg); if(res < 0){ printk("stk %s int error 7n", __func__); goto EXIT_ERR; } res = sensor_write_reg(client, STK_WAIT_REG, stk3x1x_pfdata.wait_reg); if(res < 0){ printk("stk %s int error 8n", __func__); goto EXIT_ERR; } value = 0x0; res = sensor_write_reg(client, STK_INT_REG, value); if(res < 0){ printk("stk %s int error 10n", __func__); goto EXIT_ERR; } stk3x1x_set_ps_thd_h(client, stk3x1x_pfdata.ps_thd_h); stk3x1x_set_ps_thd_l(client, stk3x1x_pfdata.ps_thd_l); printk("stk %s initing n", __func__); #ifdef STK_TUNE0 stk_ps_tune_zero_init(client); #endif #ifdef STK_ALS_FIR memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); atomic_set(&ps_data->firlength, STK_FIR_LEN); #endif atomic_set(&ps_data->recv_reg, 0); ps_data->ps_enabled = false; ps_data->ps_distance_last = 1; ps_data->stk_max_min_diff = stk3x1x_pfdata.stk_max_min_diff; ps_data->stk_lt_n_ct = stk3x1x_pfdata.stk_lt_n_ct; ps_data->stk_ht_n_ct = stk3x1x_pfdata.stk_ht_n_ct; ps_data->ps_thd_h = stk3x1x_pfdata.ps_thd_h; ps_data->ps_thd_l = stk3x1x_pfdata.ps_thd_l; printk("stk %s init successful n", __func__); val = sensor_read_reg(client, STK_INT_REG); val &= ~INT_CTRL_PS_AND_LS; if (sensor->pdata->irq_enable) val |= PS_INT_ENABLE; else val &= ~PS_INT_ENABLE; res = sensor_write_reg(client, STK_INT_REG, val); if (res) { dev_err(&client->dev, "%s:write INT_CTRL failn", __func__); return res; } return 0; EXIT_ERR: printk(KERN_ERR "stk init fail dev: %dn", res); return res; } static int proximity_sensor_report_value(struct i2c_client *client) { struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; int value = 0; char buffer[2] = {0}; //printk("stk %sn", __func__); if(sensor->ops->read_len < 2) //sensor->ops->read_len = 1 { printk("%s:lenth is error,len=%dn",__func__,sensor->ops->read_len); return -1; } value = sensor_read_reg(client, STK_FLAG_REG); if(value < 0) { printk("stk %s read STK_FLAG_REG, ret=%dn", __func__, value); return value; } if(!(value & STK_FLG_PSDR_MASK)) return 0; memset(buffer, 0, 2); buffer[0] = sensor->ops->read_reg; result = sensor_rx_data(client, buffer, sensor->ops->read_len); if(result) { printk("%s:line=%d,errorn",__func__,__LINE__); return result; } value = (buffer[0] << 8) | buffer[1]; if(value < 0) { #ifdef STK_DEBUG_PRINTF printk("stk %s: value == %d return n",__func__,value); #endif return result; } #ifdef STK_DEBUG_PRINTF printk("stk %s: value == %d n",__func__,value); #endif #ifdef STK_TUNE0 if(ps_data->tune_zero_init_proc) stk_tune_zero_get_ps_data(client, value); else stk_ps_tune_zero_func_fae(client, value); #endif stk_ps_report(client, value); if (sensor->pdata->irq_enable && sensor->ops->int_status_reg) { value = sensor_read_reg(client, sensor->ops->int_status_reg); if (value & STK_FLAG_PSINT) { value &= ~STK_FLAG_PSINT; result = sensor_write_reg (client, sensor->ops->int_status_reg, value); if (result) { dev_err(&client->dev, "%s:write status reg errorn", __func__); return result; } } } return result; } struct sensor_operate proximity_stk3x1x_ops = { .name = "ps_stk3x1x", .type = SENSOR_TYPE_PROXIMITY, //sensor type and it should be correct .id_i2c = PROXIMITY_ID_STK3X1X, //i2c id number .read_reg = STK_DATA1_PS_REG, //read data .read_len = 2, //data length .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register .id_data = SENSOR_UNKNOW_DATA, //device id .precision = 16, //16 bits .ctrl_reg = STK_STATE_REG, //enable or disable .int_status_reg = STK_FLAG_REG, //intterupt status register .range = {0,1}, //range .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, .active = proximity_sensor_active, .init = proximity_sensor_init, .report = proximity_sensor_report_value, // int brightness[2];//backlight min_brightness max_brightness // int int_ctrl_reg; // int (*suspend)(struct i2c_client *client); // int (*resume)(struct i2c_client *client); // struct miscdevice *misc_dev; }; /****************operate according to sensor chip:end************/ static int psensor_stk3x1x_probe(struct i2c_client *client, const struct i2c_device_id *devid) { return sensor_register_device(client, NULL, devid, &proximity_stk3x1x_ops); } static int psensor_stk3x1x_remove(struct i2c_client *client) { return sensor_unregister_device(client, NULL, &proximity_stk3x1x_ops); } static const struct i2c_device_id psensor_stk3x1x_id[] = { {"ps_stk3x1x", PROXIMITY_ID_STK3X1X}, {} }; MODULE_DEVICE_TABLE(i2c, psensor_stk3x1x_id); static struct i2c_driver psensor_stk3x1x_driver = { .probe = psensor_stk3x1x_probe, .remove = psensor_stk3x1x_remove, .shutdown = sensor_shutdown, .id_table = psensor_stk3x1x_id, .driver = { .name = "psensor_stk3x1x", #ifdef CONFIG_PM .pm = &sensor_pm_ops, #endif }, }; module_i2c_driver(psensor_stk3x1x_driver); MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sensortek.com.tw>"); MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION);
3、stk3x1x.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34/* * * $Id: stk3x1x.h * * Copyright (C) 2012~2013 Lex Hsieh <lex_hsieh@sensortek.com.tw> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * */ #ifndef __STK3X1X_H__ #define __STK3X1X_H__ /* platform data */ struct stk3x1x_platform_data { uint8_t state_reg; uint8_t psctrl_reg; uint8_t alsctrl_reg; uint8_t ledctrl_reg; uint8_t wait_reg; uint16_t ps_thd_h; uint16_t ps_thd_l; //int int_pin; uint32_t transmittance; uint16_t stk_max_min_diff; uint16_t stk_lt_n_ct; uint16_t stk_ht_n_ct; }; #endif // __STK3X1X_H__
4、在device 添加两个宏,编译hardware下相关的代码。
三、打开settings下面的自动调光选项,驱动会轮询环境光的亮度。
四、测试距离传感器。
1、需要搞个小app打开这个服务,app的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57package com.giada.proximity; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.os.PowerManager; import android.util.Log; public class MainActivity extends AppCompatActivity { private Sensor sensor; private SensorManager sm; private SensorEventListener listener; private String TAG = "TYPE_PROXIMITY"; private PowerManager localPowerManager = null;// 电源管理对象 private PowerManager.WakeLock localWakeLock = null;// 电源锁 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sm=(SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor=sm.getDefaultSensor(Sensor.TYPE_PROXIMITY); localPowerManager = (PowerManager) getSystemService(POWER_SERVICE); listener=new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub //获得距离传感器中的数值,这里只有一个距离 float[] values = event.values; Log.i(TAG,"onSensorChanged values[0]="+values[0]+" maxrange="+sensor.getMaximumRange()); if (values[0] == 0.0) {// 贴近手机 Log.d(TAG, "The object is near to sensor!"); } else {// 远离手机 Log.d(TAG, "The object is far to sensor!"); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub Log.i(TAG,"onAccuracyChanged"); } }; sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL); } }
2、app界面,打开就可以了
3、当有物体靠近和远离传感器的时候会产生中断,上层可以用getevent -l 看到上报的信息,有ABS_DISTANCE的信息,这个就是距离传感器上报上来的信息。
4、adb logcat看上层的log,物体接近的时候onSensorChanged values[0]=0.0,物体远离的时候onSensorChanged values[0]=9.3,有一个问题9.0这个数在哪里设置呢?答案是hardwarerockchipsensorstnusensors.h
五、参考文章
https://www.jb51.net/article/127408.htm (Android编程基于距离传感器控制手机屏幕熄灭的方法详解)
STK3311-X传感器调试_晓风凌殇的博客-CSDN博客_stk3311
Android——距离传感器(PROXIMITY)的应用_Li_peilun的博客-CSDN博客
最后
以上就是高贵画板最近收集整理的关于2022-04-13 Ambient Light & Proximity Sensor 光感和距离传感器 STK3311X调试记录 RK3566 Android11平台的全部内容,更多相关2022-04-13内容请搜索靠谱客的其他文章。
发表评论 取消回复