1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include "drv_als_ps_ir_liteon_ap3216c.h"
6 #include "ulog/ulog.h"
7 #include <aos/kernel.h>
8 
9 static i2c_dev_t i2c_dev;
10 
11 #define PKG_USING_AP3216C
12 
13 #ifdef PKG_USING_AP3216C
14 
15 #define  AP3216C_I2C_PORT 1
16 #define AP3216C_ADDR      0x1e
17 
18 // System Register
19 #define AP3216C_SYS_CONFIGURATION_REG    0x00
20 #define AP3216C_SYS_INT_STATUS_REG       0x01
21 #define AP3216C_SYS_INT_CLEAR_MANNER_REG 0x02
22 #define AP3216C_IR_DATA_L_REG            0x0A
23 #define AP3216C_IR_DATA_H_REG            0x0B
24 #define AP3216C_ALS_DATA_L_REG           0x0C
25 #define AP3216C_ALS_DATA_H_REG           0x0D
26 #define AP3216C_PS_DATA_L_REG            0x0E
27 #define AP3216C_PS_DATA_H_REG            0x0F
28 
29 // ALS Register
30 #define AP3216C_ALS_CONFIGURATION_REG    0x10
31 #define AP3216C_ALS_CALIBRATION_REG      0x19
32 #define AP3216C_ALS_THRESHOLD_LOW_L_REG  0x1A
33 #define AP3216C_ALS_THRESHOLD_LOW_H_REG  0x1B
34 #define AP3216C_ALS_THRESHOLD_HIGH_L_REG 0x1C
35 #define AP3216C_ALS_THRESHOLD_HIGH_H_REG 0x1D
36 
37 // PS Register
38 #define AP3216C_PS_CONFIGURATION_REG    0x20
39 #define AP3216C_PS_LED_DRIVER_REG       0x21
40 #define AP3216C_PS_INT_FORM_REG         0x22
41 #define AP3216C_PS_MEAN_TIME_REG        0x23
42 #define AP3216C_PS_LED_WAITING_TIME_REG 0x24
43 #define AP3216C_PS_CALIBRATION_L_REG    0x28
44 #define AP3216C_PS_CALIBRATION_H_REG    0x29
45 #define AP3216C_PS_THRESHOLD_LOW_L_REG  0x2A
46 #define AP3216C_PS_THRESHOLD_LOW_H_REG  0x2B
47 #define AP3216C_PS_THRESHOLD_HIGH_L_REG 0x2C
48 #define AP3216C_PS_THRESHOLD_HIGH_H_REG 0x2D
49 
50 /* 写寄存器的值 */
write_reg(uint8_t reg,uint8_t data)51 static void write_reg(uint8_t reg, uint8_t data)
52 {
53     sensor_i2c_mem_write(AP3216C_I2C_PORT, AP3216C_ADDR, reg, 1, &data, 1, 100);
54 }
55 
56 /* 读寄存器的值 */
read_regs(uint8_t reg,uint8_t len,uint8_t * buf)57 static void read_regs(uint8_t reg, uint8_t len, uint8_t *buf)
58 {
59     sensor_i2c_mem_read(AP3216C_I2C_PORT, AP3216C_ADDR, reg, 1, buf, len, 100);
60 }
61 
62 /* 软件复位传感器 */
reset_sensor(void)63 static void reset_sensor(void)
64 {
65     write_reg(AP3216C_SYS_CONFIGURATION_REG, AP3216C_MODE_SW_RESET); // reset
66 }
67 
68 /**
69  * This function is convenient to getting data except including high and low
70  * data for this sensor. note:after reading lower register first,reading higher
71  * add one.
72  */
read_low_and_high(uint8_t reg,uint8_t len)73 static uint32_t read_low_and_high(uint8_t reg, uint8_t len)
74 {
75     uint32_t data;
76     uint8_t  buf = 0;
77 
78     read_regs(reg, len, &buf); // 读低字节
79     data = buf;
80     read_regs(reg + 1, len, &buf);  // 读高字节
81     data = data + (buf << len * 8); // 合并数据
82 
83     return data;
84 }
85 
86 /**
87  * This function is only used to set threshold without filtering times
88  *
89  * @param cmd first register , and other cmd count by it.
90  * @param threshold threshold and filtering times of als threshold
91  */
set_als_threshold(ap3216c_cmd_t cmd,ap3216c_threshold_t threshold)92 static void set_als_threshold(ap3216c_cmd_t cmd, ap3216c_threshold_t threshold)
93 {
94     uint8_t Resolution;
95     double  DB = 1.0;
96 
97     /* 读光照强度的范围 */
98     ap3216c_get_param(AP3216C_ALS_RANGE, &Resolution);
99 
100     if (Resolution == AP3216C_ALS_RANGE_20661) {
101         // 光照强度范围 0 - 20661
102         DB = 0.35; // 光照强度的分辨率
103     } else if (Resolution == AP3216C_ALS_RANGE_5162) {
104         // 光照强度范围 0 - 5162
105         DB = 0.0788; // 光照强度的分辨率
106     } else if (Resolution == AP3216C_ALS_RANGE_1291) {
107         // 光照强度范围 0 - 1291
108         DB = 0.0197; // 光照强度的分辨率
109     } else if (Resolution == AP3216C_ALS_RANGE_323) {
110         // 光照强度范围 0 - 323
111         DB = 0.0049; // 光照强度的分辨率
112     }
113 
114     threshold.min /= DB; // 根据不同的分辨率来设置
115     threshold.max /= DB;
116 
117     ap3216c_set_param(cmd, (threshold.min & 0xff));
118     ap3216c_set_param((ap3216c_cmd_t)(cmd + 1), (threshold.min >> 8));
119     ap3216c_set_param((ap3216c_cmd_t)(cmd + 2), (threshold.max & 0xff));
120     ap3216c_set_param((ap3216c_cmd_t)(cmd + 3), threshold.max >> 8);
121 }
122 
set_ps_threshold(ap3216c_cmd_t cmd,ap3216c_threshold_t threshold)123 static void set_ps_threshold(ap3216c_cmd_t cmd, ap3216c_threshold_t threshold)
124 {
125     if (threshold.min > 1020) {
126         // 大于1020 时需要设置低字节的低两位
127         ap3216c_set_param(cmd, (threshold.min - 1020 & 0x03));
128     }
129 
130     ap3216c_set_param((ap3216c_cmd_t)(cmd + 1),
131                       threshold.min / 4); // 设置高字节参数
132 
133     if (threshold.max > 1020) {
134         // 大于1020 时需要设置低字节的低两位
135         ap3216c_set_param((ap3216c_cmd_t)(cmd + 2),
136                           (threshold.max - 1020 & 0x03));
137     }
138 
139     ap3216c_set_param((ap3216c_cmd_t)(cmd + 3),
140                       threshold.max / 4); // 设置高字节参数
141 }
142 
143 /**
144  * This function reads status register by ap3216c sensor measurement
145  *
146  * @param no
147  *
148  * @return status register value.
149  */
150 
ap3216c_get_IntStatus(void)151 uint8_t ap3216c_get_IntStatus(void)
152 {
153     uint8_t IntStatus;
154 
155     /* 读中断状态寄存器 */
156 
157     read_regs(AP3216C_SYS_INT_STATUS_REG, 1, &IntStatus);
158     // IntStatus 第 0 位表示 ALS 中断,第 1 位表示 PS 中断。
159 
160     return IntStatus; // 返回状态
161 }
162 
ap3216c_int_init(void)163 static void ap3216c_int_init(void) { ; }
164 
165 /**
166  * @brief  配置 中断输入引脚
167  * @param  无
168  * @retval 无
169  */
ap3216c_int_Config(void)170 void ap3216c_int_Config(void) { ; }
171 
172 /**
173  * This function initializes ap3216c registered device driver
174  *
175  * @param no
176  *
177  * @return the ap3216c device.
178  */
ap3216c_init(void)179 void ap3216c_init(void)
180 {
181     int32_t ret = sensor_i2c_open(AP3216C_I2C_PORT, AP3216C_ADDR, I2C_BUS_BIT_RATES_100K, 0);
182     if (ret) {
183         LOGI("SENSOR", "sensor i2c open failed, ret:%d\n", ret);
184         return;
185     }
186 
187     /* reset ap3216c */
188     reset_sensor();
189     aos_msleep(100);
190     ap3216c_set_param(AP3216C_SYSTEM_MODE, AP3216C_MODE_ALS_AND_PS);
191     aos_msleep(150); // delay at least 112.5ms
192 
193     ap3216c_int_Config();
194     ap3216c_int_init();
195 }
196 
ap3216c_deinit(void)197 void ap3216c_deinit(void)
198 {
199     int32_t ret = sensor_i2c_close(AP3216C_I2C_PORT);
200     if (ret) {
201         LOGE("SENSOR", "sensor i2c close failed, ret:%d\n", ret);
202     }
203 
204     return;
205 }
206 
207 /**
208  * This function reads light by ap3216c sensor measurement
209  *
210  * @param no
211  *
212  * @return the ambient light converted to float data.
213  */
ap3216c_read_ambient_light(void)214 uint16_t ap3216c_read_ambient_light(void)
215 {
216     uint16_t brightness = 0; // default error data
217     uint16_t read_data;
218     uint8_t  range;
219 
220     read_data = (uint16_t)read_low_and_high(AP3216C_ALS_DATA_L_REG, 1);
221     ap3216c_get_param(AP3216C_ALS_RANGE, &range);
222     if (range == AP3216C_ALS_RANGE_20661) {
223         brightness =
224             0.35 * read_data; // sensor ambient light converse to reality
225     } else if (range == AP3216C_ALS_RANGE_5162) {
226         brightness =
227             0.0788 * read_data; // sensor ambient light converse to reality
228     } else if (range == AP3216C_ALS_RANGE_1291) {
229         brightness =
230             0.0197 * read_data; // sensor ambient light converse to reality
231     } else if (range == AP3216C_ALS_RANGE_323) {
232         brightness =
233             0.0049 * read_data; // sensor ambient light converse to reality
234     }
235     return brightness;
236 }
237 
238 /**
239  * This function reads proximity by ap3216c sensor measurement
240  *
241  * @param no
242  *
243  * @return the proximity data.
244  */
ap3216c_read_ps_data(void)245 uint16_t ap3216c_read_ps_data(void)
246 {
247     uint16_t proximity = 0;
248 
249     uint32_t read_data;
250     read_data = read_low_and_high(AP3216C_PS_DATA_L_REG, 1); // read two data
251     // printf("ap3216c_read_ps_data read_data %d\n",read_data);
252     if (1 == ((read_data >> 6) & 0x01 || (read_data >> 14) & 0x01)) {
253         return proximity =
254                    55555; // 红外过高(IR),PS无效 返回一个 55555 的无效数据
255     }
256 
257     proximity =
258         (read_data & 0x000f) + (((read_data >> 8) & 0x3f)
259                                 << 4); // sensor proximity converse to reality
260 
261     proximity |= read_data & 0x8000; // 取最高位,0 表示物体远离,1 表示物体靠近
262 
263     return proximity; // proximity 后十位是数据位,最高位为状态位
264 }
265 
266 /**
267  * This function reads ir by ap3216c sensor measurement
268  *
269  * @param no
270  *
271  * @return the ir data.
272  */
ap3216c_read_ir_data(void)273 uint16_t ap3216c_read_ir_data(void)
274 {
275     uint16_t proximity = 0;
276 
277     uint32_t read_data;
278     read_data = read_low_and_high(AP3216C_IR_DATA_L_REG, 1); // read two data
279     // printf("ap3216c_read_ir_data read_data %d\n",read_data);
280     proximity =
281         (read_data & 0x0003) +
282         ((read_data >> 8) & 0xFF); // sensor proximity converse to reality
283 
284     return proximity;
285 }
286 
287 /**
288  * This function sets parameter of ap3216c sensor
289  *
290  * @param cmd the parameter cmd of device
291  * @param value for setting value in cmd register
292  *
293  * @return the setting parameter status,RT_EOK reprensents setting successfully.
294  */
ap3216c_set_param(ap3216c_cmd_t cmd,uint8_t value)295 void ap3216c_set_param(ap3216c_cmd_t cmd, uint8_t value)
296 {
297     switch (cmd) {
298         case AP3216C_SYSTEM_MODE:
299         {
300             /* default 000,power down */
301             write_reg(AP3216C_SYS_CONFIGURATION_REG, value);
302             break;
303         }
304         case AP3216C_INT_PARAM:
305         {
306             write_reg(AP3216C_SYS_INT_CLEAR_MANNER_REG, value);
307 
308             break;
309         }
310 
311         case AP3216C_ALS_RANGE:
312         {
313             uint8_t args;
314 
315             read_regs(AP3216C_ALS_CONFIGURATION_REG, 1, &args);
316             args &= 0xcf;
317             args |= value << 4;
318             write_reg(AP3216C_ALS_CONFIGURATION_REG, args);
319 
320             break;
321         }
322         case AP3216C_ALS_PERSIST:
323         {
324             uint8_t args = 0;
325 
326             read_regs(AP3216C_ALS_CONFIGURATION_REG, 1, &args);
327             args &= 0xf0;
328             args |= value;
329             write_reg(AP3216C_ALS_CONFIGURATION_REG, args);
330 
331             break;
332         }
333         case AP3216C_ALS_LOW_THRESHOLD_L:
334         {
335             write_reg(AP3216C_ALS_THRESHOLD_LOW_L_REG, value);
336 
337             break;
338         }
339         case AP3216C_ALS_LOW_THRESHOLD_H:
340         {
341             write_reg(AP3216C_ALS_THRESHOLD_LOW_H_REG, value);
342 
343             break;
344         }
345         case AP3216C_ALS_HIGH_THRESHOLD_L:
346         {
347             write_reg(AP3216C_ALS_THRESHOLD_HIGH_L_REG, value);
348 
349             break;
350         }
351         case AP3216C_ALS_HIGH_THRESHOLD_H:
352         {
353             write_reg(AP3216C_ALS_THRESHOLD_HIGH_H_REG, value);
354 
355             break;
356         }
357         case AP3216C_PS_GAIN:
358         {
359             uint8_t args = 0;
360 
361             read_regs(AP3216C_PS_CONFIGURATION_REG, 1, &args);
362             args &= 0xf3;
363             args |= value;
364             write_reg(AP3216C_PS_CONFIGURATION_REG, args);
365 
366             break;
367         }
368         case AP3216C_PS_PERSIST:
369         {
370             uint8_t args = 0;
371 
372             read_regs(AP3216C_PS_CONFIGURATION_REG, 1, &args);
373             args &= 0xfc;
374             args |= value;
375             write_reg(AP3216C_PS_CONFIGURATION_REG, args);
376 
377             break;
378         }
379         case AP3216C_PS_LOW_THRESHOLD_L:
380         {
381             write_reg(AP3216C_PS_THRESHOLD_LOW_L_REG, value);
382 
383             break;
384         }
385         case AP3216C_PS_LOW_THRESHOLD_H:
386         {
387             write_reg(AP3216C_PS_THRESHOLD_LOW_H_REG, value);
388 
389             break;
390         }
391         case AP3216C_PS_HIGH_THRESHOLD_L:
392         {
393             write_reg(AP3216C_PS_THRESHOLD_HIGH_L_REG, value);
394 
395             break;
396         }
397         case AP3216C_PS_HIGH_THRESHOLD_H:
398         {
399             write_reg(AP3216C_PS_THRESHOLD_HIGH_H_REG, value);
400 
401             break;
402         }
403 
404         default:
405         {
406             break;
407         }
408     }
409 }
410 
411 /**
412  * This function gets parameter of ap3216c sensor
413  *
414  * @param cmd the parameter cmd of device
415  * @param value to get value in cmd register
416  *
417  * @return the getting parameter status,RT_EOK reprensents getting successfully.
418  */
ap3216c_get_param(ap3216c_cmd_t cmd,uint8_t * value)419 void ap3216c_get_param(ap3216c_cmd_t cmd, uint8_t *value)
420 {
421     switch (cmd) {
422         case AP3216C_SYSTEM_MODE:
423         {
424             read_regs(AP3216C_SYS_CONFIGURATION_REG, 1, value);
425 
426             break;
427         }
428         case AP3216C_INT_PARAM:
429         {
430             read_regs(AP3216C_SYS_INT_CLEAR_MANNER_REG, 1, value);
431 
432             break;
433         }
434         case AP3216C_ALS_RANGE:
435         {
436             uint8_t temp;
437 
438             read_regs(AP3216C_ALS_CONFIGURATION_REG, 1, value);
439             temp = (*value & 0xff) >> 4;
440 
441             *value = temp;
442 
443             break;
444         }
445         case AP3216C_ALS_PERSIST:
446         {
447             uint8_t temp;
448 
449             read_regs(AP3216C_ALS_CONFIGURATION_REG, 1, value);
450             temp = *value & 0x0f;
451 
452             *value = temp;
453 
454             break;
455         }
456         case AP3216C_ALS_LOW_THRESHOLD_L:
457         {
458             read_regs(AP3216C_ALS_THRESHOLD_LOW_L_REG, 1, value);
459 
460             break;
461         }
462         case AP3216C_ALS_LOW_THRESHOLD_H:
463         {
464             read_regs(AP3216C_ALS_THRESHOLD_LOW_H_REG, 1, value);
465 
466             break;
467         }
468         case AP3216C_ALS_HIGH_THRESHOLD_L:
469         {
470             read_regs(AP3216C_ALS_THRESHOLD_HIGH_L_REG, 1, value);
471 
472             break;
473         }
474         case AP3216C_ALS_HIGH_THRESHOLD_H:
475         {
476             read_regs(AP3216C_ALS_THRESHOLD_HIGH_H_REG, 1, value);
477 
478             break;
479         }
480         case AP3216C_PS_GAIN:
481         {
482             uint8_t temp;
483 
484             read_regs(AP3216C_PS_CONFIGURATION_REG, 1, &temp);
485 
486             *value = (temp & 0xc) >> 2;
487 
488             break;
489         }
490         case AP3216C_PS_PERSIST:
491         {
492             uint8_t temp;
493 
494             read_regs(AP3216C_PS_CONFIGURATION_REG, 1, &temp);
495 
496             *value = temp & 0x3;
497 
498             break;
499         }
500         case AP3216C_PS_LOW_THRESHOLD_L:
501         {
502             read_regs(AP3216C_PS_THRESHOLD_LOW_L_REG, 1, value);
503 
504             break;
505         }
506         case AP3216C_PS_LOW_THRESHOLD_H:
507         {
508             read_regs(AP3216C_PS_THRESHOLD_LOW_H_REG, 1, value);
509             break;
510         }
511         case AP3216C_PS_HIGH_THRESHOLD_L:
512         {
513             read_regs(AP3216C_PS_THRESHOLD_HIGH_L_REG, 1, value);
514 
515             break;
516         }
517         case AP3216C_PS_HIGH_THRESHOLD_H:
518         {
519             read_regs(AP3216C_PS_THRESHOLD_HIGH_H_REG, 1, value);
520 
521             break;
522         }
523 
524         default:
525         {
526             break;
527         }
528     }
529 }
530 
531 #endif /* PKG_USING_AP3216C */
532