import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / kr076_nand / alsps / APDS9930.c
1 /* drivers/hwmon/mt6516/amit/APDS9930.c - APDS9930 ALS/PS driver
2 *
3 * Author: MingHsien Hsieh <minghsien.hsieh@mediatek.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16 #include <linux/interrupt.h>
17 #include <linux/i2c.h>
18 #include <linux/slab.h>
19 #include <linux/irq.h>
20 #include <linux/miscdevice.h>
21 #include <asm/uaccess.h>
22 #include <linux/delay.h>
23 #include <linux/input.h>
24 #include <linux/workqueue.h>
25 #include <linux/kobject.h>
26 #include <linux/earlysuspend.h>
27 #include <linux/platform_device.h>
28 #include <asm/atomic.h>
29
30 #include <mach/mt_typedefs.h>
31 #include <mach/mt_gpio.h>
32 #include <mach/mt_pm_ldo.h>
33
34 #define POWER_NONE_MACRO MT65XX_POWER_NONE
35
36 #include <linux/hwmsensor.h>
37 #include <linux/hwmsen_dev.h>
38 #include <linux/sensors_io.h>
39 #include <asm/io.h>
40 #include <cust_eint.h>
41 #include <cust_alsps.h>
42 #include "APDS9930.h"
43 #include <linux/sched.h>
44 /******************************************************************************
45 * configuration
46 *******************************************************************************/
47 /*----------------------------------------------------------------------------*/
48
49 #define APDS9930_DEV_NAME "APDS9930"
50 /*----------------------------------------------------------------------------*/
51 #define APS_TAG "[ALS/PS] "
52 #define APS_FUN(f) printk(KERN_INFO APS_TAG"%s\n", __FUNCTION__)
53 #define APS_ERR(fmt, args...) printk(KERN_ERR APS_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
54 #define APS_LOG(fmt, args...) printk(KERN_ERR APS_TAG fmt, ##args)
55 #define APS_DBG(fmt, args...) printk(KERN_INFO APS_TAG fmt, ##args)
56
57 #define I2C_FLAG_WRITE 0
58 #define I2C_FLAG_READ 1
59
60
61 /******************************************************************************
62 * extern functions
63 *******************************************************************************/
64 extern void mt_eint_mask(unsigned int eint_num);
65 extern void mt_eint_unmask(unsigned int eint_num);
66 extern void mt_eint_set_hw_debounce(unsigned int eint_num, unsigned int ms);
67 extern void mt_eint_set_polarity(unsigned int eint_num, unsigned int pol);
68 extern unsigned int mt_eint_set_sens(unsigned int eint_num, unsigned int sens);
69 extern void mt_eint_registration(unsigned int eint_num, unsigned int flow, void (EINT_FUNC_PTR)(void), unsigned int is_auto_umask);
70 extern void mt_eint_print_status(void);
71
72 /*----------------------------------------------------------------------------*/
73 static struct i2c_client *APDS9930_i2c_client = NULL;
74 /*----------------------------------------------------------------------------*/
75 static const struct i2c_device_id APDS9930_i2c_id[] = {{APDS9930_DEV_NAME,0},{}};
76 static struct i2c_board_info __initdata i2c_APDS9930={ I2C_BOARD_INFO("APDS9930", 0x39)};
77 /*----------------------------------------------------------------------------*/
78 static int APDS9930_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
79 static int APDS9930_i2c_remove(struct i2c_client *client);
80 static int APDS9930_i2c_detect(struct i2c_client *client, struct i2c_board_info *info);
81 /*----------------------------------------------------------------------------*/
82 static int APDS9930_i2c_suspend(struct i2c_client *client, pm_message_t msg);
83 static int APDS9930_i2c_resume(struct i2c_client *client);
84
85 static DEFINE_MUTEX(APDS9930_mutex);
86
87
88 static struct APDS9930_priv *g_APDS9930_ptr = NULL;
89
90 struct PS_CALI_DATA_STRUCT
91 {
92 int close;
93 int far_away;
94 int valid;
95 } ;
96
97 static struct PS_CALI_DATA_STRUCT ps_cali={0,0,0};
98 static int intr_flag_value = 0;
99 static unsigned long long int_top_time = 0;
100 /*----------------------------------------------------------------------------*/
101 typedef enum {
102 CMC_BIT_ALS = 1,
103 CMC_BIT_PS = 2,
104 } CMC_BIT;
105 /*----------------------------------------------------------------------------*/
106 struct APDS9930_i2c_addr { /*define a series of i2c slave address*/
107 u8 write_addr;
108 u8 ps_thd; /*PS INT threshold*/
109 };
110 /*----------------------------------------------------------------------------*/
111 struct APDS9930_priv {
112 struct alsps_hw *hw;
113 struct i2c_client *client;
114 struct work_struct eint_work;
115
116 /*i2c address group*/
117 struct APDS9930_i2c_addr addr;
118
119 /*misc*/
120 u16 als_modulus;
121 atomic_t i2c_retry;
122 atomic_t als_suspend;
123 atomic_t als_debounce; /*debounce time after enabling als*/
124 atomic_t als_deb_on; /*indicates if the debounce is on*/
125 atomic_t als_deb_end; /*the jiffies representing the end of debounce*/
126 atomic_t ps_mask; /*mask ps: always return far away*/
127 atomic_t ps_debounce; /*debounce time after enabling ps*/
128 atomic_t ps_deb_on; /*indicates if the debounce is on*/
129 atomic_t ps_deb_end; /*the jiffies representing the end of debounce*/
130 atomic_t ps_suspend;
131
132
133 /*data*/
134 u16 als;
135 u16 ps;
136 u8 _align;
137 u16 als_level_num;
138 u16 als_value_num;
139 u32 als_level[C_CUST_ALS_LEVEL-1];
140 u32 als_value[C_CUST_ALS_LEVEL];
141 int ps_cali;
142
143 atomic_t als_cmd_val; /*the cmd value can't be read, stored in ram*/
144 atomic_t ps_cmd_val; /*the cmd value can't be read, stored in ram*/
145 atomic_t ps_thd_val_high; /*the cmd value can't be read, stored in ram*/
146 atomic_t ps_thd_val_low; /*the cmd value can't be read, stored in ram*/
147 ulong enable; /*enable mask*/
148 ulong pending_intr; /*pending interrupt*/
149
150 /*early suspend*/
151 #if defined(CONFIG_HAS_EARLYSUSPEND)
152 struct early_suspend early_drv;
153 #endif
154 };
155 /*----------------------------------------------------------------------------*/
156 static struct i2c_driver APDS9930_i2c_driver = {
157 .probe = APDS9930_i2c_probe,
158 .remove = APDS9930_i2c_remove,
159 .detect = APDS9930_i2c_detect,
160 .suspend = APDS9930_i2c_suspend,
161 .resume = APDS9930_i2c_resume,
162 .id_table = APDS9930_i2c_id,
163 .driver = {
164 .name = APDS9930_DEV_NAME,
165 },
166 };
167
168 static struct APDS9930_priv *APDS9930_obj = NULL;
169 static struct platform_driver APDS9930_alsps_driver;
170 /*------------------------i2c function for 89-------------------------------------*/
171 int APDS9930_i2c_master_operate(struct i2c_client *client, const char *buf, int count, int i2c_flag)
172 {
173 int res = 0;
174 mutex_lock(&APDS9930_mutex);
175 switch(i2c_flag){
176 case I2C_FLAG_WRITE:
177 client->addr &=I2C_MASK_FLAG;
178 res = i2c_master_send(client, buf, count);
179 client->addr &=I2C_MASK_FLAG;
180 break;
181
182 case I2C_FLAG_READ:
183 client->addr &=I2C_MASK_FLAG;
184 client->addr |=I2C_WR_FLAG;
185 client->addr |=I2C_RS_FLAG;
186 res = i2c_master_send(client, buf, count);
187 client->addr &=I2C_MASK_FLAG;
188 break;
189 default:
190 APS_LOG("APDS9930_i2c_master_operate i2c_flag command not support!\n");
191 break;
192 }
193 if(res <= 0)
194 {
195 goto EXIT_ERR;
196 }
197 mutex_unlock(&APDS9930_mutex);
198 return res;
199 EXIT_ERR:
200 mutex_unlock(&APDS9930_mutex);
201 APS_ERR("APDS9930_i2c_transfer fail\n");
202 return res;
203 }
204
205 /*----------------------------------------------------------------------------*/
206 int APDS9930_get_addr(struct alsps_hw *hw, struct APDS9930_i2c_addr *addr)
207 {
208 if(!hw || !addr)
209 {
210 return -EFAULT;
211 }
212 addr->write_addr= hw->i2c_addr[0];
213 return 0;
214 }
215 /*----------------------------------------------------------------------------*/
216 static void APDS9930_power(struct alsps_hw *hw, unsigned int on)
217 {
218 static unsigned int power_on = 0;
219
220 //APS_LOG("power %s\n", on ? "on" : "off");
221
222 if(hw->power_id != POWER_NONE_MACRO)
223 {
224 if(power_on == on)
225 {
226 APS_LOG("ignore power control: %d\n", on);
227 }
228 else if(on)
229 {
230 if(!hwPowerOn(hw->power_id, hw->power_vol, "APDS9930"))
231 {
232 APS_ERR("power on fails!!\n");
233 }
234 }
235 else
236 {
237 if(!hwPowerDown(hw->power_id, "APDS9930"))
238 {
239 APS_ERR("power off fail!!\n");
240 }
241 }
242 }
243 power_on = on;
244 }
245 /*----------------------------------------------------------------------------*/
246 static long APDS9930_enable_als(struct i2c_client *client, int enable)
247 {
248 struct APDS9930_priv *obj = i2c_get_clientdata(client);
249 u8 databuf[2];
250 long res = 0;
251
252 databuf[0]= APDS9930_CMM_ENABLE;
253 res = APDS9930_i2c_master_operate(client, databuf, 0x101, I2C_FLAG_READ);
254 if(res <= 0)
255 {
256 goto EXIT_ERR;
257 }
258 //APS_LOG("APDS9930_CMM_ENABLE als value = %x\n",databuf[0]);
259
260 if(enable)
261 {
262 databuf[1] = databuf[0]|0x03;
263 databuf[0] = APDS9930_CMM_ENABLE;
264 //APS_LOG("APDS9930_CMM_ENABLE enable als value = %x\n",databuf[1]);
265 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
266 if(res <= 0)
267 {
268 goto EXIT_ERR;
269 }
270 atomic_set(&obj->als_deb_on, 1);
271 atomic_set(&obj->als_deb_end, jiffies+atomic_read(&obj->als_debounce)/(1000/HZ));
272 }
273 else {
274 if(test_bit(CMC_BIT_PS, &obj->enable))
275 databuf[1] = databuf[0]&0xFD;
276 else
277 databuf[1] = databuf[0]&0xF8;
278
279 databuf[0] = APDS9930_CMM_ENABLE;
280 //APS_LOG("APDS9930_CMM_ENABLE disable als value = %x\n",databuf[1]);
281 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
282 if(res <= 0)
283 {
284 goto EXIT_ERR;
285 }
286 }
287 return 0;
288
289 EXIT_ERR:
290 APS_ERR("APDS9930_enable_als fail\n");
291 return res;
292 }
293
294 /*----------------------------------------------------------------------------*/
295 static long APDS9930_enable_ps(struct i2c_client *client, int enable)
296 {
297 struct APDS9930_priv *obj = i2c_get_clientdata(client);
298 u8 databuf[2];
299 long res = 0;
300
301 databuf[0]= APDS9930_CMM_ENABLE;
302 res = APDS9930_i2c_master_operate(client, databuf, 0x101, I2C_FLAG_READ);
303 if(res <= 0)
304 {
305 goto EXIT_ERR;
306 }
307
308 //APS_LOG("APDS9930_CMM_ENABLE ps value = %x\n",databuf[0]);
309
310 if(enable)
311 {
312 databuf[1] = databuf[0]|0x05;
313 databuf[0] = APDS9930_CMM_ENABLE;
314 //APS_LOG("APDS9930_CMM_ENABLE enable ps value = %x\n",databuf[1]);
315 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
316 if(res <= 0)
317 {
318 goto EXIT_ERR;
319 }
320 atomic_set(&obj->ps_deb_on, 1);
321 atomic_set(&obj->ps_deb_end, jiffies+atomic_read(&obj->ps_debounce)/(1000/HZ));
322 }
323 else{
324 if(test_bit(CMC_BIT_ALS, &obj->enable))
325 databuf[1] = databuf[0]&0xFB;
326 else
327 databuf[1] = databuf[0]&0xF8;
328
329 databuf[0] = APDS9930_CMM_ENABLE;
330 //APS_LOG("APDS9930_CMM_ENABLE disable ps value = %x\n",databuf[1]);
331 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
332 if(res <= 0)
333 {
334 goto EXIT_ERR;
335 }
336 /*fix bug*/
337 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
338 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_low)) & 0x00FF);
339 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
340 if(res <= 0)
341 {
342 goto EXIT_ERR;
343 }
344 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
345 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_low)) & 0xFF00) >> 8);
346 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
347 if(res <= 0)
348 {
349 goto EXIT_ERR;
350 }
351 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
352 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_high)) & 0x00FF);
353 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
354 if(res <= 0)
355 {
356 goto EXIT_ERR;
357 }
358 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
359 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_high)) & 0xFF00) >> 8);;
360 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
361 if(res <= 0)
362 {
363 goto EXIT_ERR;
364 }
365 /*fix bug*/
366 }
367 return 0;
368
369 EXIT_ERR:
370 APS_ERR("APDS9930_enable_ps fail\n");
371 return res;
372 }
373 /*----------------------------------------------------------------------------*/
374 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
375 static int APDS9930_check_and_clear_intr(struct i2c_client *client)
376 {
377 int res,intp,intl;
378 u8 buffer[2];
379
380 if (mt_get_gpio_in(GPIO_ALS_EINT_PIN) == 1) /*skip if no interrupt*/
381 return 0;
382
383 buffer[0] = APDS9930_CMM_STATUS;
384 res = APDS9930_i2c_master_operate(client, buffer, 0x101, I2C_FLAG_READ);
385 if(res <= 0)
386 {
387 goto EXIT_ERR;
388 }
389
390 res = 0;
391 intp = 0;
392 intl = 0;
393 if(0 != (buffer[0] & 0x20))
394 {
395 res = 1;
396 intp = 1;
397 }
398 if(0 != (buffer[0] & 0x10))
399 {
400 res = 1;
401 intl = 1;
402 }
403
404 if(1 == res)
405 {
406 if((1 == intp) && (0 == intl))
407 {
408 buffer[0] = (TAOS_TRITON_CMD_REG|TAOS_TRITON_CMD_SPL_FN|0x05);
409 }
410 else if((0 == intp) && (1 == intl))
411 {
412 buffer[0] = (TAOS_TRITON_CMD_REG|TAOS_TRITON_CMD_SPL_FN|0x06);
413 }
414 else
415 {
416 buffer[0] = (TAOS_TRITON_CMD_REG|TAOS_TRITON_CMD_SPL_FN|0x07);
417 }
418
419 res = APDS9930_i2c_master_operate(client, buffer, 0x1, I2C_FLAG_WRITE);
420 if(res <= 0)
421 {
422 goto EXIT_ERR;
423 }
424 else
425 {
426 res = 0;
427 }
428 }
429
430 return res;
431
432 EXIT_ERR:
433 APS_ERR("APDS9930_check_and_clear_intr fail\n");
434 return 1;
435 }
436 /*----------------------------------------------------------------------------*/
437
438 /*yucong add for interrupt mode support MTK inc 2012.3.7*/
439 static int APDS9930_check_intr(struct i2c_client *client)
440 {
441 int res,intp,intl;
442 u8 buffer[2];
443
444 if (mt_get_gpio_in(GPIO_ALS_EINT_PIN) == 1) /*skip if no interrupt*/
445 return 0;
446
447 buffer[0] = APDS9930_CMM_STATUS;
448 res = APDS9930_i2c_master_operate(client, buffer, 0x101, I2C_FLAG_READ);
449 if(res <= 0)
450 {
451 goto EXIT_ERR;
452 }
453 res = 0;
454 intp = 0;
455 intl = 0;
456 if(0 != (buffer[0] & 0x20))
457 {
458 res = 0;
459 intp = 1;
460 }
461 if(0 != (buffer[0] & 0x10))
462 {
463 res = 0;
464 intl = 1;
465 }
466
467 return res;
468
469 EXIT_ERR:
470 APS_ERR("APDS9930_check_intr fail\n");
471 return 1;
472 }
473
474 static int APDS9930_clear_intr(struct i2c_client *client)
475 {
476 int res;
477 u8 buffer[2];
478
479 buffer[0] = (TAOS_TRITON_CMD_REG|TAOS_TRITON_CMD_SPL_FN|0x07);
480 res = APDS9930_i2c_master_operate(client, buffer, 0x1, I2C_FLAG_WRITE);
481 if(res <= 0)
482 {
483 goto EXIT_ERR;
484 }
485 else
486 {
487 res = 0;
488 }
489 return res;
490
491 EXIT_ERR:
492 APS_ERR("APDS9930_check_and_clear_intr fail\n");
493 return 1;
494 }
495
496
497 /*-----------------------------------------------------------------------------*/
498 void APDS9930_eint_func(void)
499 {
500 struct APDS9930_priv *obj = g_APDS9930_ptr;
501 if(!obj)
502 {
503 return;
504 }
505 int_top_time = sched_clock();
506 schedule_work(&obj->eint_work);
507 }
508
509 /*----------------------------------------------------------------------------*/
510 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
511 int APDS9930_setup_eint(struct i2c_client *client)
512 {
513 struct APDS9930_priv *obj = i2c_get_clientdata(client);
514
515 g_APDS9930_ptr = obj;
516
517 mt_set_gpio_dir(GPIO_ALS_EINT_PIN, GPIO_DIR_IN);
518 mt_set_gpio_mode(GPIO_ALS_EINT_PIN, GPIO_ALS_EINT_PIN_M_EINT);
519 mt_set_gpio_pull_enable(GPIO_ALS_EINT_PIN, TRUE);
520 mt_set_gpio_pull_select(GPIO_ALS_EINT_PIN, GPIO_PULL_UP);
521
522 mt_eint_set_hw_debounce(CUST_EINT_ALS_NUM, CUST_EINT_ALS_DEBOUNCE_CN);
523 mt_eint_registration(CUST_EINT_ALS_NUM, CUST_EINT_ALS_TYPE, APDS9930_eint_func, 0);
524
525 mt_eint_unmask(CUST_EINT_ALS_NUM);
526 return 0;
527 }
528
529 /*----------------------------------------------------------------------------*/
530
531 static int APDS9930_init_client(struct i2c_client *client)
532 {
533 struct APDS9930_priv *obj = i2c_get_clientdata(client);
534 u8 databuf[2];
535 int res = 0;
536
537 databuf[0] = (TAOS_TRITON_CMD_REG|TAOS_TRITON_CMD_SPL_FN|0x00);
538 res = APDS9930_i2c_master_operate(client, databuf, 0x1, I2C_FLAG_WRITE);
539 if(res <= 0)
540 {
541 goto EXIT_ERR;
542 }
543
544 databuf[0] = APDS9930_CMM_ENABLE;
545 if(obj->hw->polling_mode_ps == 1)
546 databuf[1] = 0x08;
547 if(obj->hw->polling_mode_ps == 0)
548 databuf[1] = 0x28;
549 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
550 if(res <= 0)
551 {
552 goto EXIT_ERR;
553 }
554
555 databuf[0] = APDS9930_CMM_ATIME;
556 databuf[1] = 0xF6;
557 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
558 if(res <= 0)
559 {
560 goto EXIT_ERR;
561 }
562
563 databuf[0] = APDS9930_CMM_PTIME;
564 databuf[1] = 0xFF;
565 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
566 if(res <= 0)
567 {
568 goto EXIT_ERR;
569 }
570
571 databuf[0] = APDS9930_CMM_WTIME;
572 databuf[1] = 0xFC;
573 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
574 if(res <= 0)
575 {
576 goto EXIT_ERR;
577 }
578 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
579 if(0 == obj->hw->polling_mode_ps)
580 {
581 if(1 == ps_cali.valid)
582 {
583 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
584 databuf[1] = (u8)(ps_cali.far_away & 0x00FF);
585 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
586 if(res <= 0)
587 {
588 goto EXIT_ERR;
589 }
590 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
591 databuf[1] = (u8)((ps_cali.far_away & 0xFF00) >> 8);
592 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
593 if(res <= 0)
594 {
595 goto EXIT_ERR;
596 }
597 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
598 databuf[1] = (u8)(ps_cali.close & 0x00FF);
599 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
600 if(res <= 0)
601 {
602 goto EXIT_ERR;
603 }
604 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
605 databuf[1] = (u8)((ps_cali.close & 0xFF00) >> 8);;
606 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
607 if(res <= 0)
608 {
609 goto EXIT_ERR;
610 }
611 }
612 else
613 {
614 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
615 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_low)) & 0x00FF);
616 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
617 if(res <= 0)
618 {
619 goto EXIT_ERR;
620 }
621 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
622 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_low)) & 0xFF00) >> 8);
623 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
624 if(res <= 0)
625 {
626 goto EXIT_ERR;
627 }
628 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
629 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_high)) & 0x00FF);
630 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
631 if(res <= 0)
632 {
633 goto EXIT_ERR;
634 }
635 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
636 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_high)) & 0xFF00) >> 8);;
637 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
638 if(res <= 0)
639 {
640 goto EXIT_ERR;
641 }
642
643 }
644
645 databuf[0] = APDS9930_CMM_Persistence;
646 databuf[1] = 0x20;
647 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
648 if(res <= 0)
649 {
650 goto EXIT_ERR;
651 }
652
653 }
654
655 databuf[0] = APDS9930_CMM_CONFIG;
656 databuf[1] = 0x00;
657 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
658 if(res <= 0)
659 {
660 goto EXIT_ERR;
661 }
662
663 /*Lenovo-sw chenlj2 add 2011-06-03,modified pulse 2 to 4 */
664 databuf[0] = APDS9930_CMM_PPCOUNT;
665 databuf[1] = APDS9930_CMM_PPCOUNT_VALUE;
666 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
667 if(res <= 0)
668 {
669 goto EXIT_ERR;
670 }
671
672 /*Lenovo-sw chenlj2 add 2011-06-03,modified gain 16 to 1 */
673 databuf[0] = APDS9930_CMM_CONTROL;
674 databuf[1] = APDS9930_CMM_CONTROL_VALUE;
675 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
676 if(res <= 0)
677 {
678 goto EXIT_ERR;
679 }
680 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
681 if((res = APDS9930_setup_eint(client))!=0)
682 {
683 APS_ERR("setup eint: %d\n", res);
684 return res;
685 }
686 if((res = APDS9930_check_and_clear_intr(client)))
687 {
688 APS_ERR("check/clear intr: %d\n", res);
689 return res;
690 }
691
692 return APDS9930_SUCCESS;
693
694 EXIT_ERR:
695 APS_ERR("init dev: %d\n", res);
696 return res;
697 }
698
699 /******************************************************************************
700 * Function Configuration
701 ******************************************************************************/
702 int APDS9930_read_als(struct i2c_client *client, u16 *data)
703 {
704 struct APDS9930_priv *obj = i2c_get_clientdata(client);
705 u16 c0_value, c1_value;
706 u32 c0_nf, c1_nf;
707 u8 buffer[2];
708 u16 atio;
709 int res = 0;
710
711 if(client == NULL)
712 {
713 APS_DBG("CLIENT CANN'T EQUL NULL\n");
714 return -1;
715 }
716
717 buffer[0]=APDS9930_CMM_C0DATA_L;
718 res = APDS9930_i2c_master_operate(client, buffer, 0x201, I2C_FLAG_READ);
719 if(res <= 0)
720 {
721 goto EXIT_ERR;
722 }
723
724 c0_value = buffer[0] | (buffer[1]<<8);
725 c0_nf = obj->als_modulus*c0_value;
726 //APS_LOG("c0_value=%d, c0_nf=%d, als_modulus=%d\n", c0_value, c0_nf, obj->als_modulus);
727
728 buffer[0]=APDS9930_CMM_C1DATA_L;
729 res = APDS9930_i2c_master_operate(client, buffer, 0x201, I2C_FLAG_READ);
730 if(res <= 0)
731 {
732 goto EXIT_ERR;
733 }
734
735 c1_value = buffer[0] | (buffer[1]<<8);
736 c1_nf = obj->als_modulus*c1_value;
737 //APS_LOG("c1_value=%d, c1_nf=%d, als_modulus=%d\n", c1_value, c1_nf, obj->als_modulus);
738
739 if((c0_value > c1_value) &&(c0_value < 50000))
740 { /*Lenovo-sw chenlj2 add 2011-06-03,add {*/
741 atio = (c1_nf*100)/c0_nf;
742
743 //APS_LOG("atio = %d\n", atio);
744 if(atio<30)
745 {
746 *data = (13*c0_nf - 24*c1_nf)/10000;
747 }
748 else if(atio>= 30 && atio<38) /*Lenovo-sw chenlj2 add 2011-06-03,modify > to >=*/
749 {
750 *data = (16*c0_nf - 35*c1_nf)/10000;
751 }
752 else if(atio>= 38 && atio<45) /*Lenovo-sw chenlj2 add 2011-06-03,modify > to >=*/
753 {
754 *data = (9*c0_nf - 17*c1_nf)/10000;
755 }
756 else if(atio>= 45 && atio<54) /*Lenovo-sw chenlj2 add 2011-06-03,modify > to >=*/
757 {
758 *data = (6*c0_nf - 10*c1_nf)/10000;
759 }
760 else
761 *data = 0;
762 /*Lenovo-sw chenlj2 add 2011-06-03,add }*/
763 }
764 else if (c0_value > 50000)
765 {
766 *data = 65535;
767 }
768 else if(c0_value == 0)
769 {
770 *data = 0;
771 }
772 else
773 {
774 APS_DBG("APDS9930_read_als als_value is invalid!!\n");
775 return -1;
776 }
777
778 //APS_LOG("APDS9930_read_als als_value_lux = %d\n", *data);
779 return 0;
780
781
782
783 EXIT_ERR:
784 APS_ERR("APDS9930_read_ps fail\n");
785 return res;
786 }
787 int APDS9930_read_als_ch0(struct i2c_client *client, u16 *data)
788 {
789 //struct APDS9930_priv *obj = i2c_get_clientdata(client);
790 u16 c0_value;
791 u8 buffer[2];
792 int res = 0;
793
794 if(client == NULL)
795 {
796 APS_DBG("CLIENT CANN'T EQUL NULL\n");
797 return -1;
798 }
799
800 //get adc channel 0 value
801 buffer[0]=APDS9930_CMM_C0DATA_L;
802 res = APDS9930_i2c_master_operate(client, buffer, 0x201, I2C_FLAG_READ);
803 if(res <= 0)
804 {
805 goto EXIT_ERR;
806 }
807 c0_value = buffer[0] | (buffer[1]<<8);
808 *data = c0_value;
809 //APS_LOG("c0_value=%d\n", c0_value);
810 return 0;
811
812
813
814 EXIT_ERR:
815 APS_ERR("APDS9930_read_ps fail\n");
816 return res;
817 }
818 /*----------------------------------------------------------------------------*/
819
820 static int APDS9930_get_als_value(struct APDS9930_priv *obj, u16 als)
821 {
822 int idx;
823 int invalid = 0;
824 for(idx = 0; idx < obj->als_level_num; idx++)
825 {
826 if(als < obj->hw->als_level[idx])
827 {
828 break;
829 }
830 }
831
832 if(idx >= obj->als_value_num)
833 {
834 APS_ERR("APDS9930_get_als_value exceed range\n");
835 idx = obj->als_value_num - 1;
836 }
837
838 if(1 == atomic_read(&obj->als_deb_on))
839 {
840 unsigned long endt = atomic_read(&obj->als_deb_end);
841 if(time_after(jiffies, endt))
842 {
843 atomic_set(&obj->als_deb_on, 0);
844 }
845
846 if(1 == atomic_read(&obj->als_deb_on))
847 {
848 invalid = 1;
849 }
850 }
851
852 if(!invalid)
853 {
854 #if defined(MTK_AAL_SUPPORT)
855 int level_high = obj->hw->als_level[idx];
856 int level_low = (idx > 0) ? obj->hw->als_level[idx-1] : 0;
857 int level_diff = level_high - level_low;
858 int value_high = obj->hw->als_value[idx];
859 int value_low = (idx > 0) ? obj->hw->als_value[idx-1] : 0;
860 int value_diff = value_high - value_low;
861 int value = 0;
862
863 if ((level_low >= level_high) || (value_low >= value_high))
864 value = value_low;
865 else
866 value = (level_diff * value_low + (als - level_low) * value_diff + ((level_diff + 1) >> 1)) / level_diff;
867
868 APS_DBG("ALS: %d [%d, %d] => %d [%d, %d] \n", als, level_low, level_high, value, value_low, value_high);
869 return value;
870 #endif
871 //APS_ERR("ALS: %05d => %05d\n", als, obj->hw->als_value[idx]);
872 return obj->hw->als_value[idx];
873 }
874 else
875 {
876 //APS_ERR("ALS: %05d => %05d (-1)\n", als, obj->hw->als_value[idx]);
877 return -1;
878 }
879 }
880 /*----------------------------------------------------------------------------*/
881 long APDS9930_read_ps(struct i2c_client *client, u16 *data)
882 {
883 struct APDS9930_priv *obj = i2c_get_clientdata(client);
884 u8 buffer[2];
885 u16 temp_data;
886 long res = 0;
887
888 if(client == NULL)
889 {
890 APS_DBG("CLIENT CANN'T EQUL NULL\n");
891 return -1;
892 }
893
894 buffer[0]=APDS9930_CMM_PDATA_L;
895 res = APDS9930_i2c_master_operate(client, buffer, 0x201, I2C_FLAG_READ);
896 if(res <= 0)
897 {
898 goto EXIT_ERR;
899 }
900
901 temp_data = buffer[0] | (buffer[1]<<8);
902 //APS_LOG("yucong APDS9930_read_ps ps_data=%d, low:%d high:%d", *data, buffer[0], buffer[1]);
903 if(temp_data < obj->ps_cali)
904 *data = 0;
905 else
906 *data = temp_data - obj->ps_cali;
907 return 0;
908 return 0;
909
910 EXIT_ERR:
911 APS_ERR("APDS9930_read_ps fail\n");
912 return res;
913 }
914 /*----------------------------------------------------------------------------*/
915 static int APDS9930_get_ps_value(struct APDS9930_priv *obj, u16 ps)
916 {
917 int val;// mask = atomic_read(&obj->ps_mask);
918 int invalid = 0;
919 static int val_temp=1;
920
921 if(ps_cali.valid == 1)
922 {
923 if((ps >ps_cali.close))
924 {
925 val = 0; /*close*/
926 val_temp = 0;
927 intr_flag_value = 1;
928 }
929
930 else if((ps < ps_cali.far_away))
931 {
932 val = 1; /*far away*/
933 val_temp = 1;
934 intr_flag_value = 0;
935 }
936 else
937 val = val_temp;
938
939 APS_LOG("APDS9930_get_ps_value val = %d",val);
940 }
941 else
942 {
943 if((ps > atomic_read(&obj->ps_thd_val_high)))
944 {
945 val = 0; /*close*/
946 val_temp = 0;
947 intr_flag_value = 1;
948 }
949 else if((ps < atomic_read(&obj->ps_thd_val_low)))
950 {
951 val = 1; /*far away*/
952 val_temp = 1;
953 intr_flag_value = 0;
954 }
955 else
956 val = val_temp;
957
958 }
959
960 if(atomic_read(&obj->ps_suspend))
961 {
962 invalid = 1;
963 }
964 else if(1 == atomic_read(&obj->ps_deb_on))
965 {
966 unsigned long endt = atomic_read(&obj->ps_deb_end);
967 if(time_after(jiffies, endt))
968 {
969 atomic_set(&obj->ps_deb_on, 0);
970 }
971
972 if (1 == atomic_read(&obj->ps_deb_on))
973 {
974 invalid = 1;
975 }
976 }
977 else if (obj->als > 45000)
978 {
979 //invalid = 1;
980 APS_DBG("ligh too high will result to failt proximiy\n");
981 return 1; /*far away*/
982 }
983
984 if(!invalid)
985 {
986 //APS_DBG("PS: %05d => %05d\n", ps, val);
987 return val;
988 }
989 else
990 {
991 return -1;
992 }
993 }
994
995
996 /*----------------------------------------------------------------------------*/
997 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
998 //#define DEBUG_APDS9930
999 static void APDS9930_eint_work(struct work_struct *work)
1000 {
1001 struct APDS9930_priv *obj = (struct APDS9930_priv *)container_of(work, struct APDS9930_priv, eint_work);
1002 int err;
1003 hwm_sensor_data sensor_data;
1004 u8 databuf[3];
1005 int res = 0;
1006
1007 if((err = APDS9930_check_intr(obj->client)))
1008 {
1009 APS_ERR("APDS9930_eint_work check intrs: %d\n", err);
1010 }
1011 else
1012 {
1013 //get raw data
1014 APDS9930_read_ps(obj->client, &obj->ps);
1015 APDS9930_read_als_ch0(obj->client, &obj->als);
1016 APS_LOG("APDS9930_eint_work rawdata ps=%d als_ch0=%d!\n",obj->ps,obj->als);
1017 APS_LOG("APDS9930 int top half time = %lld\n", int_top_time);
1018
1019 if(obj->als > 40000)
1020 {
1021 APS_LOG("APDS9930_eint_work ALS too large may under lighting als_ch0=%d!\n",obj->als);
1022 return;
1023 }
1024 sensor_data.values[0] = APDS9930_get_ps_value(obj, obj->ps);
1025 sensor_data.value_divide = 1;
1026 sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM;
1027
1028 #ifdef DEBUG_APDS9930
1029 databuf[0]= APDS9930_CMM_ENABLE;
1030 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x101, I2C_FLAG_READ);
1031 if(res <= 0)
1032 {
1033 goto EXIT_ERR;
1034 }
1035 APS_LOG("APDS9930_eint_work APDS9930_CMM_ENABLE ps value = %x\n",databuf[0]);
1036
1037 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
1038 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x201, I2C_FLAG_READ);
1039 if(res <= 0)
1040 {
1041 goto EXIT_ERR;
1042 }
1043 APS_LOG("APDS9930_eint_work APDS9930_CMM_INT_LOW_THD_LOW before databuf[0]=%d databuf[1]=%d!\n",databuf[0],databuf[1]);
1044
1045 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
1046 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x201, I2C_FLAG_READ);
1047 if(res <= 0)
1048 {
1049 goto EXIT_ERR;
1050 }
1051 APS_LOG("APDS9930_eint_work APDS9930_CMM_INT_HIGH_THD_LOW before databuf[0]=%d databuf[1]=%d!\n",databuf[0],databuf[1]);
1052 #endif
1053 /*singal interrupt function add*/
1054 if(intr_flag_value){
1055 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
1056 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_low)) & 0x00FF);
1057 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1058 if(res <= 0)
1059 {
1060 goto EXIT_ERR;
1061 }
1062
1063 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
1064 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_low)) & 0xFF00) >> 8);
1065 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1066 if(res <= 0)
1067 {
1068 goto EXIT_ERR;
1069 }
1070 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
1071 databuf[1] = (u8)(0x00FF);
1072 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1073 if(res <= 0)
1074 {
1075 goto EXIT_ERR;
1076 }
1077
1078 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
1079 databuf[1] = (u8)((0xFF00) >> 8);
1080 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1081 if(res <= 0)
1082 {
1083 goto EXIT_ERR;
1084 }
1085
1086 }
1087 else{
1088 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
1089 databuf[1] = (u8)(0 & 0x00FF);
1090 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1091 if(res <= 0)
1092 {
1093 goto EXIT_ERR;
1094 }
1095
1096 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
1097 databuf[1] = (u8)((0 & 0xFF00) >> 8);
1098 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1099 if(res <= 0)
1100 {
1101 goto EXIT_ERR;
1102 }
1103
1104 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
1105 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_high)) & 0x00FF);
1106 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1107 if(res <= 0)
1108 {
1109 goto EXIT_ERR;
1110 }
1111
1112 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
1113 databuf[1] = (u8)(((atomic_read(&obj->ps_thd_val_high)) & 0xFF00) >> 8);
1114 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x2, I2C_FLAG_WRITE);
1115 res = i2c_master_send(obj->client, databuf, 0x2);
1116 if(res <= 0)
1117 {
1118 goto EXIT_ERR;
1119 }
1120 }
1121
1122 //let up layer to know
1123 #ifdef DEBUG_APDS9930
1124 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
1125 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x201, I2C_FLAG_READ);
1126 if(res <= 0)
1127 {
1128 goto EXIT_ERR;
1129 }
1130 APS_LOG("APDS9930_eint_work APDS9930_CMM_INT_LOW_THD_LOW after databuf[0]=%d databuf[1]=%d!\n",databuf[0],databuf[1]);
1131
1132 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
1133 res = APDS9930_i2c_master_operate(obj->client, databuf, 0x201, I2C_FLAG_READ);
1134 if(res <= 0)
1135 {
1136 goto EXIT_ERR;
1137 }
1138 APS_LOG("APDS9930_eint_work APDS9930_CMM_INT_HIGH_THD_LOW after databuf[0]=%d databuf[1]=%d!\n",databuf[0],databuf[1]);
1139 #endif
1140 if((err = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data)))
1141 {
1142 APS_ERR("call hwmsen_get_interrupt_data fail = %d\n", err);
1143 }
1144 }
1145
1146 APDS9930_clear_intr(obj->client);
1147 mt_eint_unmask(CUST_EINT_ALS_NUM);
1148 return;
1149 EXIT_ERR:
1150 APDS9930_clear_intr(obj->client);
1151 mt_eint_unmask(CUST_EINT_ALS_NUM);
1152 APS_ERR("i2c_transfer error = %d\n", res);
1153 return;
1154 }
1155
1156
1157 /******************************************************************************
1158 * Function Configuration
1159 ******************************************************************************/
1160 static int APDS9930_open(struct inode *inode, struct file *file)
1161 {
1162 file->private_data = APDS9930_i2c_client;
1163
1164 if (!file->private_data)
1165 {
1166 APS_ERR("null pointer!!\n");
1167 return -EINVAL;
1168 }
1169
1170 return nonseekable_open(inode, file);
1171 }
1172 /*----------------------------------------------------------------------------*/
1173 static int APDS9930_release(struct inode *inode, struct file *file)
1174 {
1175 file->private_data = NULL;
1176 return 0;
1177 }
1178 /*----------------------------------------------------------------------------*/
1179 static int set_psensor_threshold(struct i2c_client *client)
1180 {
1181 struct APDS9930_priv *obj = i2c_get_clientdata(client);
1182 u8 databuf[3];
1183 int res = 0;
1184 APS_ERR("set_psensor_threshold function high: 0x%x, low:0x%x\n",atomic_read(&obj->ps_thd_val_high),atomic_read(&obj->ps_thd_val_low));
1185
1186 databuf[0] = APDS9930_CMM_INT_LOW_THD_LOW;
1187 databuf[1] = (u8)(atomic_read(&obj->ps_thd_val_low) & 0x00FF);
1188 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
1189 if(res <= 0)
1190 {
1191 return -1;
1192 }
1193 databuf[0] = APDS9930_CMM_INT_LOW_THD_HIGH;
1194 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_low) & 0xFF00) >> 8);
1195 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
1196 if(res <= 0)
1197 {
1198 return -1;
1199 }
1200 databuf[0] = APDS9930_CMM_INT_HIGH_THD_LOW;
1201 databuf[1] = (u8)(atomic_read(&obj->ps_thd_val_high) & 0x00FF);
1202 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
1203 if(res <= 0)
1204 {
1205 return -1;
1206 }
1207 databuf[0] = APDS9930_CMM_INT_HIGH_THD_HIGH;
1208 databuf[1] = (u8)((atomic_read(&obj->ps_thd_val_high) & 0xFF00) >> 8);;
1209 res = APDS9930_i2c_master_operate(client, databuf, 0x2, I2C_FLAG_WRITE);
1210 if(res <= 0)
1211 {
1212 return -1;
1213 }
1214
1215 return 0;
1216 }
1217
1218 /*----------------------------------------------------------------------------*/
1219 static long APDS9930_unlocked_ioctl(struct file *file, unsigned int cmd,
1220 unsigned long arg)
1221 {
1222 struct i2c_client *client = (struct i2c_client*)file->private_data;
1223 struct APDS9930_priv *obj = i2c_get_clientdata(client);
1224 long err = 0;
1225 void __user *ptr = (void __user*) arg;
1226 int dat;
1227 uint32_t enable;
1228 int ps_result;
1229 int ps_cali;
1230 int threshold[2];
1231
1232 switch (cmd)
1233 {
1234 case ALSPS_SET_PS_MODE:
1235 if(copy_from_user(&enable, ptr, sizeof(enable)))
1236 {
1237 err = -EFAULT;
1238 goto err_out;
1239 }
1240 if(enable)
1241 {
1242 if((err = APDS9930_enable_ps(obj->client, 1)))
1243 {
1244 APS_ERR("enable ps fail: %ld\n", err);
1245 goto err_out;
1246 }
1247
1248 set_bit(CMC_BIT_PS, &obj->enable);
1249 }
1250 else
1251 {
1252 if((err = APDS9930_enable_ps(obj->client, 0)))
1253 {
1254 APS_ERR("disable ps fail: %ld\n", err);
1255 goto err_out;
1256 }
1257
1258 clear_bit(CMC_BIT_PS, &obj->enable);
1259 }
1260 break;
1261
1262 case ALSPS_GET_PS_MODE:
1263 enable = test_bit(CMC_BIT_PS, &obj->enable) ? (1) : (0);
1264 if(copy_to_user(ptr, &enable, sizeof(enable)))
1265 {
1266 err = -EFAULT;
1267 goto err_out;
1268 }
1269 break;
1270
1271 case ALSPS_GET_PS_DATA:
1272 if((err = APDS9930_read_ps(obj->client, &obj->ps)))
1273 {
1274 goto err_out;
1275 }
1276
1277 dat = APDS9930_get_ps_value(obj, obj->ps);
1278 if(copy_to_user(ptr, &dat, sizeof(dat)))
1279 {
1280 err = -EFAULT;
1281 goto err_out;
1282 }
1283 break;
1284
1285 case ALSPS_GET_PS_RAW_DATA:
1286 if((err = APDS9930_read_ps(obj->client, &obj->ps)))
1287 {
1288 goto err_out;
1289 }
1290
1291 dat = obj->ps;
1292 if(copy_to_user(ptr, &dat, sizeof(dat)))
1293 {
1294 err = -EFAULT;
1295 goto err_out;
1296 }
1297 break;
1298
1299 case ALSPS_SET_ALS_MODE:
1300 if(copy_from_user(&enable, ptr, sizeof(enable)))
1301 {
1302 err = -EFAULT;
1303 goto err_out;
1304 }
1305 if(enable)
1306 {
1307 if((err = APDS9930_enable_als(obj->client, 1)))
1308 {
1309 APS_ERR("enable als fail: %ld\n", err);
1310 goto err_out;
1311 }
1312 set_bit(CMC_BIT_ALS, &obj->enable);
1313 }
1314 else
1315 {
1316 if((err = APDS9930_enable_als(obj->client, 0)))
1317 {
1318 APS_ERR("disable als fail: %ld\n", err);
1319 goto err_out;
1320 }
1321 clear_bit(CMC_BIT_ALS, &obj->enable);
1322 }
1323 break;
1324
1325 case ALSPS_GET_ALS_MODE:
1326 enable = test_bit(CMC_BIT_ALS, &obj->enable) ? (1) : (0);
1327 if(copy_to_user(ptr, &enable, sizeof(enable)))
1328 {
1329 err = -EFAULT;
1330 goto err_out;
1331 }
1332 break;
1333
1334 case ALSPS_GET_ALS_DATA:
1335 if((err = APDS9930_read_als(obj->client, &obj->als)))
1336 {
1337 goto err_out;
1338 }
1339
1340 dat = APDS9930_get_als_value(obj, obj->als);
1341 if(copy_to_user(ptr, &dat, sizeof(dat)))
1342 {
1343 err = -EFAULT;
1344 goto err_out;
1345 }
1346 break;
1347
1348 case ALSPS_GET_ALS_RAW_DATA:
1349 if((err = APDS9930_read_als(obj->client, &obj->als)))
1350 {
1351 goto err_out;
1352 }
1353
1354 dat = obj->als;
1355 if(copy_to_user(ptr, &dat, sizeof(dat)))
1356 {
1357 err = -EFAULT;
1358 goto err_out;
1359 }
1360 break;
1361 /*----------------------------------for factory mode test---------------------------------------*/
1362 case ALSPS_GET_PS_TEST_RESULT:
1363 if((err = APDS9930_read_ps(obj->client, &obj->ps)))
1364 {
1365 goto err_out;
1366 }
1367 if(obj->ps > atomic_read(&obj->ps_thd_val_high))
1368 {
1369 ps_result = 0;
1370 }
1371 else ps_result = 1;
1372
1373 if(copy_to_user(ptr, &ps_result, sizeof(ps_result)))
1374 {
1375 err = -EFAULT;
1376 goto err_out;
1377 }
1378 break;
1379
1380 case ALSPS_IOCTL_CLR_CALI:
1381 if(copy_from_user(&dat, ptr, sizeof(dat)))
1382 {
1383 err = -EFAULT;
1384 goto err_out;
1385 }
1386 if(dat == 0)
1387 obj->ps_cali = 0;
1388 break;
1389
1390 case ALSPS_IOCTL_GET_CALI:
1391 ps_cali = obj->ps_cali ;
1392 if(copy_to_user(ptr, &ps_cali, sizeof(ps_cali)))
1393 {
1394 err = -EFAULT;
1395 goto err_out;
1396 }
1397 break;
1398
1399 case ALSPS_IOCTL_SET_CALI:
1400 if(copy_from_user(&ps_cali, ptr, sizeof(ps_cali)))
1401 {
1402 err = -EFAULT;
1403 goto err_out;
1404 }
1405
1406 obj->ps_cali = ps_cali;
1407 break;
1408
1409 case ALSPS_SET_PS_THRESHOLD:
1410 if(copy_from_user(threshold, ptr, sizeof(threshold)))
1411 {
1412 err = -EFAULT;
1413 goto err_out;
1414 }
1415 APS_ERR("%s set threshold high: 0x%x, low: 0x%x\n", __func__, threshold[0],threshold[1]);
1416 atomic_set(&obj->ps_thd_val_high, (threshold[0]+obj->ps_cali));
1417 atomic_set(&obj->ps_thd_val_low, (threshold[1]+obj->ps_cali));//need to confirm
1418
1419 set_psensor_threshold(obj->client);
1420
1421 break;
1422
1423 case ALSPS_GET_PS_THRESHOLD_HIGH:
1424 threshold[0] = atomic_read(&obj->ps_thd_val_high) - obj->ps_cali;
1425 APS_ERR("%s get threshold high: 0x%x\n", __func__, threshold[0]);
1426 if(copy_to_user(ptr, &threshold[0], sizeof(threshold[0])))
1427 {
1428 err = -EFAULT;
1429 goto err_out;
1430 }
1431 break;
1432
1433 case ALSPS_GET_PS_THRESHOLD_LOW:
1434 threshold[0] = atomic_read(&obj->ps_thd_val_low) - obj->ps_cali;
1435 APS_ERR("%s get threshold low: 0x%x\n", __func__, threshold[0]);
1436 if(copy_to_user(ptr, &threshold[0], sizeof(threshold[0])))
1437 {
1438 err = -EFAULT;
1439 goto err_out;
1440 }
1441 break;
1442 /*------------------------------------------------------------------------------------------*/
1443 default:
1444 APS_ERR("%s not supported = 0x%04x", __FUNCTION__, cmd);
1445 err = -ENOIOCTLCMD;
1446 break;
1447 }
1448
1449 err_out:
1450 return err;
1451 }
1452 /*----------------------------------------------------------------------------*/
1453 static struct file_operations APDS9930_fops = {
1454 .owner = THIS_MODULE,
1455 .open = APDS9930_open,
1456 .release = APDS9930_release,
1457 .unlocked_ioctl = APDS9930_unlocked_ioctl,
1458 };
1459 /*----------------------------------------------------------------------------*/
1460 static struct miscdevice APDS9930_device = {
1461 .minor = MISC_DYNAMIC_MINOR,
1462 .name = "als_ps",
1463 .fops = &APDS9930_fops,
1464 };
1465 /*----------------------------------------------------------------------------*/
1466 static int APDS9930_i2c_suspend(struct i2c_client *client, pm_message_t msg)
1467 {
1468 // struct APDS9930_priv *obj = i2c_get_clientdata(client);
1469 // int err;
1470 APS_FUN();
1471 #if 0
1472 if(msg.event == PM_EVENT_SUSPEND)
1473 {
1474 if(!obj)
1475 {
1476 APS_ERR("null pointer!!\n");
1477 return -EINVAL;
1478 }
1479
1480 atomic_set(&obj->als_suspend, 1);
1481 if(err = APDS9930_enable_als(client, 0))
1482 {
1483 APS_ERR("disable als: %d\n", err);
1484 return err;
1485 }
1486
1487 atomic_set(&obj->ps_suspend, 1);
1488 if(err = APDS9930_enable_ps(client, 0))
1489 {
1490 APS_ERR("disable ps: %d\n", err);
1491 return err;
1492 }
1493
1494 APDS9930_power(obj->hw, 0);
1495 }
1496 #endif
1497 return 0;
1498 }
1499 /*----------------------------------------------------------------------------*/
1500 static int APDS9930_i2c_resume(struct i2c_client *client)
1501 {
1502 // struct APDS9930_priv *obj = i2c_get_clientdata(client);
1503 // int err;
1504 APS_FUN();
1505 #if 0
1506 if(!obj)
1507 {
1508 APS_ERR("null pointer!!\n");
1509 return -EINVAL;
1510 }
1511
1512 APDS9930_power(obj->hw, 1);
1513 if(err = APDS9930_init_client(client))
1514 {
1515 APS_ERR("initialize client fail!!\n");
1516 return err;
1517 }
1518 atomic_set(&obj->als_suspend, 0);
1519 if(test_bit(CMC_BIT_ALS, &obj->enable))
1520 {
1521 if(err = APDS9930_enable_als(client, 1))
1522 {
1523 APS_ERR("enable als fail: %d\n", err);
1524 }
1525 }
1526 atomic_set(&obj->ps_suspend, 0);
1527 if(test_bit(CMC_BIT_PS, &obj->enable))
1528 {
1529 if(err = APDS9930_enable_ps(client, 1))
1530 {
1531 APS_ERR("enable ps fail: %d\n", err);
1532 }
1533 }
1534 #endif
1535 return 0;
1536 }
1537 /*----------------------------------------------------------------------------*/
1538 static void APDS9930_early_suspend(struct early_suspend *h)
1539 { /*early_suspend is only applied for ALS*/
1540 struct APDS9930_priv *obj = container_of(h, struct APDS9930_priv, early_drv);
1541 int err;
1542 APS_FUN();
1543
1544 if(!obj)
1545 {
1546 APS_ERR("null pointer!!\n");
1547 return;
1548 }
1549
1550 #if 1
1551 atomic_set(&obj->als_suspend, 1);
1552 if(test_bit(CMC_BIT_ALS, &obj->enable))
1553 {
1554 if((err = APDS9930_enable_als(obj->client, 0)))
1555 {
1556 APS_ERR("disable als fail: %d\n", err);
1557 }
1558 }
1559 #endif
1560 }
1561 /*----------------------------------------------------------------------------*/
1562 static void APDS9930_late_resume(struct early_suspend *h)
1563 { /*early_suspend is only applied for ALS*/
1564 struct APDS9930_priv *obj = container_of(h, struct APDS9930_priv, early_drv);
1565 int err;
1566 APS_FUN();
1567
1568 if(!obj)
1569 {
1570 APS_ERR("null pointer!!\n");
1571 return;
1572 }
1573
1574 #if 1
1575 atomic_set(&obj->als_suspend, 0);
1576 if(test_bit(CMC_BIT_ALS, &obj->enable))
1577 {
1578 if((err = APDS9930_enable_als(obj->client, 1)))
1579 {
1580 APS_ERR("enable als fail: %d\n", err);
1581
1582 }
1583 }
1584 #endif
1585 }
1586 /*----------------------------------------------------------------------------*/
1587 static int temp_als = 0;
1588 static int ALS_FLAG = 0;
1589
1590 int APDS9930_ps_operate(void* self, uint32_t command, void* buff_in, int size_in,
1591 void* buff_out, int size_out, int* actualout)
1592 {
1593 int value;
1594 int err = 0;
1595
1596 hwm_sensor_data* sensor_data;
1597 struct APDS9930_priv *obj = (struct APDS9930_priv *)self;
1598
1599 //APS_FUN(f);
1600 switch (command)
1601 {
1602 case SENSOR_DELAY:
1603 if((buff_in == NULL) || (size_in < sizeof(int)))
1604 {
1605 APS_ERR("Set delay parameter error!\n");
1606 err = -EINVAL;
1607 }
1608 // Do nothing
1609 break;
1610
1611 case SENSOR_ENABLE:
1612 if((buff_in == NULL) || (size_in < sizeof(int)))
1613 {
1614 APS_ERR("Enable sensor parameter error!\n");
1615 err = -EINVAL;
1616 }
1617 else
1618 {
1619 value = *(int *)buff_in;
1620 if(value)
1621 {
1622 if((err = APDS9930_enable_ps(obj->client, 1)))
1623 {
1624 APS_ERR("enable ps fail: %d\n", err);
1625 return -1;
1626 }
1627 set_bit(CMC_BIT_PS, &obj->enable);
1628 #if 1
1629 if(!test_bit(CMC_BIT_ALS, &obj->enable))
1630 {
1631 ALS_FLAG = 1;
1632 if((err = APDS9930_enable_als(obj->client, 1)))
1633 {
1634 APS_ERR("enable als fail: %d\n", err);
1635 return -1;
1636 }
1637 }
1638 #endif
1639 }
1640 else
1641 {
1642 if((err = APDS9930_enable_ps(obj->client, 0)))
1643 {
1644 APS_ERR("disable ps fail: %d\n", err);
1645 return -1;
1646 }
1647 clear_bit(CMC_BIT_PS, &obj->enable);
1648 #if 1
1649 if(ALS_FLAG == 1)
1650 {
1651 if((err = APDS9930_enable_als(obj->client, 0)))
1652 {
1653 APS_ERR("disable als fail: %d\n", err);
1654 return -1;
1655 }
1656 ALS_FLAG = 0;
1657 }
1658 #endif
1659 }
1660 }
1661 break;
1662
1663 case SENSOR_GET_DATA:
1664 if((buff_out == NULL) || (size_out< sizeof(hwm_sensor_data)))
1665 {
1666 APS_ERR("get sensor data parameter error!\n");
1667 err = -EINVAL;
1668 }
1669 else
1670 {
1671 sensor_data = (hwm_sensor_data *)buff_out;
1672 APDS9930_read_ps(obj->client, &obj->ps);
1673 APDS9930_read_als_ch0(obj->client, &obj->als);
1674 APS_ERR("APDS9930_ps_operate als data=%d!\n",obj->als);
1675 sensor_data->values[0] = APDS9930_get_ps_value(obj, obj->ps);
1676 sensor_data->value_divide = 1;
1677 sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM;
1678 }
1679 break;
1680 default:
1681 APS_ERR("proxmy sensor operate function no this parameter %d!\n", command);
1682 err = -1;
1683 break;
1684 }
1685
1686 return err;
1687 }
1688
1689
1690 int APDS9930_als_operate(void* self, uint32_t command, void* buff_in, int size_in,
1691 void* buff_out, int size_out, int* actualout)
1692 {
1693 int err = 0;
1694 int value;
1695 hwm_sensor_data* sensor_data;
1696 struct APDS9930_priv *obj = (struct APDS9930_priv *)self;
1697
1698 switch (command)
1699 {
1700 case SENSOR_DELAY:
1701 if((buff_in == NULL) || (size_in < sizeof(int)))
1702 {
1703 APS_ERR("Set delay parameter error!\n");
1704 err = -EINVAL;
1705 }
1706 // Do nothing
1707 break;
1708
1709 case SENSOR_ENABLE:
1710 if((buff_in == NULL) || (size_in < sizeof(int)))
1711 {
1712 APS_ERR("Enable sensor parameter error!\n");
1713 err = -EINVAL;
1714 }
1715 else
1716 {
1717 value = *(int *)buff_in;
1718 if(value)
1719 {
1720 if((err = APDS9930_enable_als(obj->client, 1)))
1721 {
1722 APS_ERR("enable als fail: %d\n", err);
1723 return -1;
1724 }
1725 set_bit(CMC_BIT_ALS, &obj->enable);
1726 }
1727 else
1728 {
1729 if((err = APDS9930_enable_als(obj->client, 0)))
1730 {
1731 APS_ERR("disable als fail: %d\n", err);
1732 return -1;
1733 }
1734 clear_bit(CMC_BIT_ALS, &obj->enable);
1735 }
1736
1737 }
1738 break;
1739
1740 case SENSOR_GET_DATA:
1741 if((buff_out == NULL) || (size_out< sizeof(hwm_sensor_data)))
1742 {
1743 APS_ERR("get sensor data parameter error!\n");
1744 err = -EINVAL;
1745 }
1746 else
1747 {
1748 sensor_data = (hwm_sensor_data *)buff_out;
1749 /*yucong MTK add for fixing known issue*/
1750 APDS9930_read_als(obj->client, &obj->als);
1751 if(obj->als == 0)
1752 {
1753 sensor_data->values[0] = temp_als;
1754 }else{
1755 u16 b[2];
1756 int i;
1757 for(i = 0;i < 2;i++){
1758 APDS9930_read_als(obj->client, &obj->als);
1759 b[i] = obj->als;
1760 }
1761 (b[1] > b[0])?(obj->als = b[0]):(obj->als = b[1]);
1762 sensor_data->values[0] = APDS9930_get_als_value(obj, obj->als);
1763 temp_als = sensor_data->values[0];
1764 }
1765 sensor_data->value_divide = 1;
1766 sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM;
1767 }
1768 break;
1769 default:
1770 APS_ERR("light sensor operate function no this parameter %d!\n", command);
1771 err = -1;
1772 break;
1773 }
1774
1775 return err;
1776 }
1777
1778
1779 /*----------------------------------------------------------------------------*/
1780 static int APDS9930_i2c_detect(struct i2c_client *client, struct i2c_board_info *info)
1781 {
1782 strcpy(info->type, APDS9930_DEV_NAME);
1783 return 0;
1784 }
1785
1786 /*----------------------------------------------------------------------------*/
1787 static int APDS9930_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
1788 {
1789 struct APDS9930_priv *obj;
1790 struct hwmsen_object obj_ps, obj_als;
1791 int err = 0;
1792
1793 if(!(obj = kzalloc(sizeof(*obj), GFP_KERNEL)))
1794 {
1795 err = -ENOMEM;
1796 goto exit;
1797 }
1798 memset(obj, 0, sizeof(*obj));
1799 APDS9930_obj = obj;
1800 obj->hw = get_cust_alsps_hw();
1801 APDS9930_get_addr(obj->hw, &obj->addr);
1802
1803 /*for interrup work mode support -- by liaoxl.lenovo 12.08.2011*/
1804 INIT_WORK(&obj->eint_work, APDS9930_eint_work);
1805 obj->client = client;
1806 i2c_set_clientdata(client, obj);
1807 atomic_set(&obj->als_debounce, 50);
1808 atomic_set(&obj->als_deb_on, 0);
1809 atomic_set(&obj->als_deb_end, 0);
1810 atomic_set(&obj->ps_debounce, 10);
1811 atomic_set(&obj->ps_deb_on, 0);
1812 atomic_set(&obj->ps_deb_end, 0);
1813 atomic_set(&obj->ps_mask, 0);
1814 atomic_set(&obj->als_suspend, 0);
1815 atomic_set(&obj->als_cmd_val, 0xDF);
1816 atomic_set(&obj->ps_cmd_val, 0xC1);
1817 atomic_set(&obj->ps_thd_val_high, obj->hw->ps_threshold_high);
1818 atomic_set(&obj->ps_thd_val_low, obj->hw->ps_threshold_low);
1819 obj->enable = 0;
1820 obj->pending_intr = 0;
1821 obj->als_level_num = sizeof(obj->hw->als_level)/sizeof(obj->hw->als_level[0]);
1822 obj->als_value_num = sizeof(obj->hw->als_value)/sizeof(obj->hw->als_value[0]);
1823 /*Lenovo-sw chenlj2 add 2011-06-03,modified gain 16 to 1/5 accoring to actual thing */
1824 obj->als_modulus = (400*100*ZOOM_TIME)/(1*150);//(1/Gain)*(400/Tine), this value is fix after init ATIME and CONTROL register value
1825 //(400)/16*2.72 here is amplify *100 //16
1826 BUG_ON(sizeof(obj->als_level) != sizeof(obj->hw->als_level));
1827 memcpy(obj->als_level, obj->hw->als_level, sizeof(obj->als_level));
1828 BUG_ON(sizeof(obj->als_value) != sizeof(obj->hw->als_value));
1829 memcpy(obj->als_value, obj->hw->als_value, sizeof(obj->als_value));
1830 atomic_set(&obj->i2c_retry, 3);
1831 set_bit(CMC_BIT_ALS, &obj->enable);
1832 set_bit(CMC_BIT_PS, &obj->enable);
1833
1834 obj->ps_cali = 0;
1835
1836 APDS9930_i2c_client = client;
1837
1838 if(1 == obj->hw->polling_mode_ps)
1839 //if (1)
1840 {
1841 obj_ps.polling = 1;
1842 }
1843 else
1844 {
1845 obj_ps.polling = 0;
1846 }
1847
1848 if((err = APDS9930_init_client(client)))
1849 {
1850 goto exit_init_failed;
1851 }
1852 APS_LOG("APDS9930_init_client() OK!\n");
1853
1854 if((err = misc_register(&APDS9930_device)))
1855 {
1856 APS_ERR("APDS9930_device register failed\n");
1857 goto exit_misc_device_register_failed;
1858 }
1859 /*
1860 if(err = APDS9930_create_attr(&APDS9930_alsps_driver.driver))
1861 {
1862 APS_ERR("create attribute err = %d\n", err);
1863 goto exit_create_attr_failed;
1864 }
1865 */
1866 obj_ps.self = APDS9930_obj;
1867
1868 obj_ps.sensor_operate = APDS9930_ps_operate;
1869 if((err = hwmsen_attach(ID_PROXIMITY, &obj_ps)))
1870 {
1871 APS_ERR("attach fail = %d\n", err);
1872 goto exit_create_attr_failed;
1873 }
1874
1875 obj_als.self = APDS9930_obj;
1876 obj_als.polling = 1;
1877 obj_als.sensor_operate = APDS9930_als_operate;
1878 if((err = hwmsen_attach(ID_LIGHT, &obj_als)))
1879 {
1880 APS_ERR("attach fail = %d\n", err);
1881 goto exit_create_attr_failed;
1882 }
1883
1884
1885 #if defined(CONFIG_HAS_EARLYSUSPEND)
1886 obj->early_drv.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1,
1887 obj->early_drv.suspend = APDS9930_early_suspend,
1888 obj->early_drv.resume = APDS9930_late_resume,
1889 register_early_suspend(&obj->early_drv);
1890 #endif
1891
1892 APS_LOG("%s: OK\n", __func__);
1893 return 0;
1894
1895 exit_create_attr_failed:
1896 misc_deregister(&APDS9930_device);
1897 exit_misc_device_register_failed:
1898 exit_init_failed:
1899 //i2c_detach_client(client);
1900 //exit_kfree:
1901 kfree(obj);
1902 exit:
1903 APDS9930_i2c_client = NULL;
1904 // MT6516_EINTIRQMask(CUST_EINT_ALS_NUM); /*mask interrupt if fail*/
1905 APS_ERR("%s: err = %d\n", __func__, err);
1906 return err;
1907 }
1908 /*----------------------------------------------------------------------------*/
1909 static int APDS9930_i2c_remove(struct i2c_client *client)
1910 {
1911 int err;
1912 /*
1913 if(err = APDS9930_delete_attr(&APDS9930_i2c_driver.driver))
1914 {
1915 APS_ERR("APDS9930_delete_attr fail: %d\n", err);
1916 }
1917 */
1918 if((err = misc_deregister(&APDS9930_device)))
1919 {
1920 APS_ERR("misc_deregister fail: %d\n", err);
1921 }
1922
1923 APDS9930_i2c_client = NULL;
1924 i2c_unregister_device(client);
1925 kfree(i2c_get_clientdata(client));
1926
1927 return 0;
1928 }
1929 /*----------------------------------------------------------------------------*/
1930 static int APDS9930_probe(struct platform_device *pdev)
1931 {
1932 struct alsps_hw *hw = get_cust_alsps_hw();
1933
1934 APDS9930_power(hw, 1);
1935 //APDS9930_force[0] = hw->i2c_num;
1936 //APDS9930_force[1] = hw->i2c_addr[0];
1937 //APS_DBG("I2C = %d, addr =0x%x\n",APDS9930_force[0],APDS9930_force[1]);
1938 if(i2c_add_driver(&APDS9930_i2c_driver))
1939 {
1940 APS_ERR("add driver error\n");
1941 return -1;
1942 }
1943 return 0;
1944 }
1945 /*----------------------------------------------------------------------------*/
1946 static int APDS9930_remove(struct platform_device *pdev)
1947 {
1948 struct alsps_hw *hw = get_cust_alsps_hw();
1949 APS_FUN();
1950 APDS9930_power(hw, 0);
1951 i2c_del_driver(&APDS9930_i2c_driver);
1952 return 0;
1953 }
1954 /*----------------------------------------------------------------------------*/
1955 static struct platform_driver APDS9930_alsps_driver = {
1956 .probe = APDS9930_probe,
1957 .remove = APDS9930_remove,
1958 .driver = {
1959 .name = "als_ps",
1960 // .owner = THIS_MODULE,
1961 }
1962 };
1963 /*----------------------------------------------------------------------------*/
1964 static int __init APDS9930_init(void)
1965 {
1966 //APS_FUN();
1967 struct alsps_hw *hw = get_cust_alsps_hw();
1968 APS_LOG("%s: i2c_number=%d\n", __func__,hw->i2c_num);
1969 i2c_register_board_info(hw->i2c_num, &i2c_APDS9930, 1);
1970 if(platform_driver_register(&APDS9930_alsps_driver))
1971 {
1972 APS_ERR("failed to register driver");
1973 return -ENODEV;
1974 }
1975 return 0;
1976 }
1977 /*----------------------------------------------------------------------------*/
1978 static void __exit APDS9930_exit(void)
1979 {
1980 APS_FUN();
1981 platform_driver_unregister(&APDS9930_alsps_driver);
1982 }
1983 /*----------------------------------------------------------------------------*/
1984 module_init(APDS9930_init);
1985 module_exit(APDS9930_exit);
1986 /*----------------------------------------------------------------------------*/
1987 MODULE_AUTHOR("Dexiang Liu");
1988 MODULE_DESCRIPTION("APDS9930 driver");
1989 MODULE_LICENSE("GPL");
1990