summaryrefslogtreecommitdiff
path: root/drivers/input/misc/epl259x.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/input/misc/epl259x.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/input/misc/epl259x.c')
-rw-r--r--drivers/input/misc/epl259x.c4645
1 files changed, 4645 insertions, 0 deletions
diff --git a/drivers/input/misc/epl259x.c b/drivers/input/misc/epl259x.c
new file mode 100644
index 00000000..81bcd79a
--- /dev/null
+++ b/drivers/input/misc/epl259x.c
@@ -0,0 +1,4645 @@
+/* drivers/i2c/chips/epl259x.c - light and proxmity sensors driver
+ * Copyright (C) 2014 ELAN Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+
+#include <linux/hrtimer.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+//#include <asm/mach-types.h>
+#include <asm/setup.h>
+#include <linux/wakelock.h>
+#include <linux/jiffies.h>
+#include <linux/i2c/epl259x.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
+
+/******************************************************************************
+* configuration
+*******************************************************************************/
+#define ALS_POLLING_MODE 1 // 1 is polling mode, 0 is interrupt mode
+#define PS_POLLING_MODE 0 // 1 is polling mode, 0 is interrupt mode
+
+#define ALS_LOW_THRESHOLD 1000
+#define ALS_HIGH_THRESHOLD 3000
+
+#define PS_LOW_THRESHOLD 3000
+#define PS_HIGH_THRESHOLD 4000
+
+#define LUX_PER_COUNT 700
+
+//platform select
+#define S5PV210 0
+#define SPREAD 1
+#define QCOM 0
+#define LEADCORE 0
+#define MARVELL 0
+
+//#define ELAN_INT_PIN 140 /*Interrupt pin setting*/
+
+//debug message
+#define COMMON_DEBUG 0
+#define ALS_DEBUG 0
+#define PS_DEBUG 1
+#define SHOW_DBG 0
+
+#define ALS_DYN_INTT 0
+#define PS_DYN_K 0
+#define PS_DYN_K_STR 0
+#define HS_ENABLE 0
+#define PS_GES 0
+
+#define ALS_LEVEL 16
+static int polling_time = 200;
+static struct i2c_client *this_client = NULL;
+static int als_level[] = {20, 45, 70, 90, 150, 300, 500, 700, 1150, 2250, 4500, 8000, 15000, 30000, 50000};
+static int als_value[] = {10, 30, 60, 80, 100, 200, 400, 600, 800, 1500, 3000, 6000, 10000, 20000, 40000, 60000};
+
+#if ALS_DYN_INTT
+//Dynamic INTT
+int dynamic_intt_idx;
+int dynamic_intt_init_idx = 1; //initial dynamic_intt_idx
+int c_gain;
+int dynamic_intt_lux = 0;
+
+uint16_t dynamic_intt_high_thr;
+uint16_t dynamic_intt_low_thr;
+uint32_t dynamic_intt_max_lux = 12000;
+uint32_t dynamic_intt_min_lux = 0;
+uint32_t dynamic_intt_min_unit = 1000;
+
+static int als_dynamic_intt_intt[] = {EPL_ALS_INTT_8192, EPL_ALS_INTT_64};
+static int als_dynamic_intt_value[] = {8192, 64};
+static int als_dynamic_intt_gain[] = {EPL_GAIN_MID, EPL_GAIN_MID};
+static int als_dynamic_intt_high_thr[] = {60000, 53000};
+static int als_dynamic_intt_low_thr[] = {200, 300};
+static int als_dynamic_intt_intt_num = sizeof(als_dynamic_intt_value)/sizeof(int);
+#endif
+
+#if ALS_DYN_INTT
+typedef enum
+{
+ CMC_BIT_LSRC_NON = 0x0,
+ CMC_BIT_LSRC_SCALE = 0x1,
+ CMC_BIT_LSRC_SLOPE = 0x2,
+ CMC_BIT_LSRC_BOTH = 0x3,
+} CMC_LSRC_REPORT_TYPE;
+#endif
+
+#if PS_DYN_K
+static int dynk_polling_delay = 200;
+int dynk_min_ps_raw_data;
+int dynk_max_ir_data;
+
+u32 dynk_thd_low = 0;
+u32 dynk_thd_high = 0;
+
+int dynk_low_offset;
+int dynk_high_offset;
+
+bool dynk_change_flag = false;
+u16 dynk_change_thd_max;
+u16 dynk_thd_offset;
+
+u8 dynk_last_status = 0;
+
+#if PS_DYN_K_STR
+bool dynk_enhance_flag = true;
+u8 dynk_enhance_integration_time;
+u8 dynk_enhance_gain;
+u8 dynk_enhance_adc;
+u16 dynk_enhance_ch0;
+u16 dynk_enhance_ch1;
+u16 dynk_enhance_max_ch0;
+#endif
+
+#endif
+
+#if HS_ENABLE
+static struct mutex hs_sensor_mutex;
+static bool hs_enable_flag = false;
+#endif
+
+#if PS_GES
+static bool ps_ges_enable_flag = false;
+u16 ges_threshold_low = 1000;
+u16 ges_threshold_high = 1500;
+#define KEYCODE_LEFT KEY_LEFTALT
+bool ps_ges_suspend_flag = false;
+#endif
+
+bool polling_flag = true;
+bool eint_flag = true;
+
+//ps calibration file location
+static const char ps_cal_file[]="/data/data/com.eminent.ps.calibration/ps.dat";
+
+//als calibration file location
+static const char als_cal_file[]="/data/data/com.eminent.ps.calibration/als.dat";
+
+static int PS_h_offset = 2000;
+static int PS_l_offset = 1000;
+static int PS_MAX_XTALK = 30000;
+
+int als_frame_time = 0;
+int ps_frame_time = 0;
+/******************************************************************************
+*******************************************************************************/
+
+#define TXBYTES 2
+#define RXBYTES 2
+
+#define PACKAGE_SIZE 8
+#define I2C_RETRY_COUNT 10
+#define EPL_DEV_NAME "epl2182_pls"
+#define DRIVER_VERSION "1.0.3"
+//struct timeval ges_enable_time;
+
+//int ges_frame_count;
+
+typedef enum
+{
+ CMC_BIT_RAW = 0x0,
+ CMC_BIT_PRE_COUNT = 0x1,
+ CMC_BIT_DYN_INT = 0x2,
+ CMC_BIT_DEF_LIGHT = 0x4,
+ CMC_BIT_TABLE = 0x8,
+} CMC_ALS_REPORT_TYPE;
+
+typedef struct _epl_raw_data
+{
+ u8 raw_bytes[PACKAGE_SIZE];
+ u16 renvo;
+} epl_raw_data;
+
+struct epl_sensor_priv
+{
+ struct i2c_client *client;
+ struct input_dev *als_input_dev;
+ struct input_dev *ps_input_dev;
+ struct workqueue_struct *epl_wq;
+ struct delayed_work eint_work;
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif
+ int intr_pin;
+ int (*power)(int on);
+
+ int ps_opened;
+ int als_opened;
+
+ int als_suspend;
+ int ps_suspend;
+
+ int lux_per_count;
+
+ int enable_pflag;
+ int enable_lflag;
+#if HS_ENABLE
+ int enable_hflag;
+ int hs_suspend;
+#endif
+#if PS_GES
+ struct input_dev *gs_input_dev;
+ int enable_gflag;
+ int ges_suspend;
+#endif
+ int read_flag;
+ int irq;
+ spinlock_t lock;
+
+#if ALS_DYN_INTT
+ uint32_t ratio;
+ uint32_t last_ratio;
+ int c_gain_h; // fluorescent (C1)
+ int c_gain_l; // incandescent (C2)
+ uint32_t lsource_thd_high; //different light source boundary (N) fluorescent (C1)
+ uint32_t lsource_thd_low; //different light source boundary (N) incandescent (C2)
+#endif
+
+ /*data*/
+ u16 als_level_num;
+ u16 als_value_num;
+ u32 als_level[ALS_LEVEL-1];
+ u32 als_value[ALS_LEVEL];
+} ;
+
+static struct platform_device *sensor_dev;
+struct epl_sensor_priv *epl_sensor_obj;
+static epl_optical_sensor epl_sensor;
+int i2c_max_count=8;
+
+static epl_raw_data gRawData;
+
+static struct wake_lock ps_lock;
+static struct mutex sensor_mutex;
+
+#if S5PV210
+static const char ElanPsensorName[]="proximity";
+static const char ElanALsensorName[]="lightsensor-level";
+#elif SPREAD
+static const char ElanPsensorName[] = "proximity";
+#elif QCOM || LEADCORE
+static const char ElanPsensorName[] = "proximity";
+static const char ElanALsensorName[] = "light";
+#elif MARVELL
+static const char ElanPsensorName[] = "alps_pxy";
+#endif
+
+#define LOG_TAG "[EPL259x] "
+#define LOG_FUN(f) printk(KERN_INFO LOG_TAG"%s\n", __FUNCTION__)
+#define LOG_INFO(fmt, args...) printk(KERN_INFO LOG_TAG fmt, ##args)
+#define LOG_ERR(fmt, args...) printk(KERN_ERR LOG_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
+
+
+void epl_sensor_update_mode(struct i2c_client *client);
+int epl_sensor_read_als_status(struct i2c_client *client);
+static int epl_sensor_setup_interrupt(struct epl_sensor_priv *epld);
+static int ps_sensing_time(int intt, int adc, int cycle);
+static int als_sensing_time(int intt, int adc, int cycle);
+
+static void epl_sensor_eint_work(struct work_struct *work);
+//static DECLARE_WORK(epl_sensor_irq_work, epl_sensor_eint_work);
+
+static void epl_sensor_polling_work(struct work_struct *work);
+static DECLARE_DELAYED_WORK(polling_work, epl_sensor_polling_work);
+
+#if PS_DYN_K
+void epl_sensor_dynk_thd_polling_work(struct work_struct *work);
+void epl_sensor_restart_dynk_polling(void);
+static DECLARE_DELAYED_WORK(dynk_thd_polling_work, epl_sensor_dynk_thd_polling_work);
+#endif
+
+
+
+
+/*
+//====================I2C write operation===============//
+*/
+static int epl_sensor_I2C_Write_Cmd(struct i2c_client *client, uint8_t regaddr, uint8_t data, uint8_t txbyte)
+{
+ uint8_t buffer[2];
+ int ret = 0;
+ int retry;
+
+ buffer[0] = regaddr ;
+ buffer[1] = data;
+
+ for(retry = 0; retry < I2C_RETRY_COUNT; retry++)
+ {
+ ret = i2c_master_send(client, buffer, txbyte);
+
+ if (ret == txbyte)
+ {
+ break;
+ }
+
+ LOG_ERR("i2c write error,TXBYTES %d\n",ret);
+ mdelay(10);
+ }
+
+
+ if(retry>=I2C_RETRY_COUNT)
+ {
+ LOG_ERR("i2c write retry over %d\n", I2C_RETRY_COUNT);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int epl_sensor_I2C_Write(struct i2c_client *client, uint8_t regaddr, uint8_t data)
+{
+ int ret = 0;
+ ret = epl_sensor_I2C_Write_Cmd(client, regaddr, data, 0x02);
+ return ret;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_I2C_Read(struct i2c_client *client, uint8_t regaddr, uint8_t bytecount)
+{
+
+ int ret = 0;
+
+
+ int retry;
+ int read_count=0, rx_count=0;
+
+ while(bytecount>0)
+ {
+ epl_sensor_I2C_Write_Cmd(client, regaddr+read_count, 0x00, 0x01);
+
+ for(retry = 0; retry < I2C_RETRY_COUNT; retry++)
+ {
+ rx_count = bytecount>i2c_max_count?i2c_max_count:bytecount;
+ ret = i2c_master_recv(client, &gRawData.raw_bytes[read_count], rx_count);
+
+ if (ret == rx_count)
+ break;
+
+ LOG_ERR("i2c read error,RXBYTES %d\r\n",ret);
+ mdelay(10);
+ }
+
+ if(retry>=I2C_RETRY_COUNT)
+ {
+ LOG_ERR("i2c read retry over %d\n", I2C_RETRY_COUNT);
+ return -EINVAL;
+ }
+ bytecount-=rx_count;
+ read_count+=rx_count;
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+static void epl_sensor_restart_polling(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ cancel_delayed_work(&polling_work);
+ queue_delayed_work(epld->epl_wq, &polling_work,msecs_to_jiffies(polling_time));
+
+}
+/*----------------------------------------------------------------------------*/
+
+#if PS_GES
+static void epl_sensor_notify_event(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ struct input_dev *idev = epld->gs_input_dev;
+
+ LOG_INFO(" --> LEFT\n\n");
+ input_report_key(idev, KEYCODE_LEFT, 1);
+ input_report_key(idev, KEYCODE_LEFT, 0);
+ input_sync(idev);
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+static void epl_sensor_report_lux(int repott_lux)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_INFO("------------------- ALS raw = %d, lux = %d\n\n",epl_sensor.als.data.channels[1], repott_lux);
+#if SPREAD || MARVELL
+ input_report_abs(epld->ps_input_dev, ABS_MISC, repott_lux);
+ input_sync(epld->ps_input_dev);
+#else
+ input_report_abs(epld->als_input_dev, ABS_MISC, repott_lux);
+ input_sync(epld->als_input_dev);
+#endif
+}
+/*----------------------------------------------------------------------------*/
+#if ALS_DYN_INTT
+long raw_convert_to_lux(u16 raw_data)
+{
+ long lux = 0;
+
+ lux = raw_data * (c_gain / als_dynamic_intt_value[dynamic_intt_idx]);
+#if ALS_DEBUG
+ LOG_INFO("[%s]:raw_data=%d, lux=%ld\r\n", __func__, raw_data, lux);
+#endif
+
+ if(lux >= (dynamic_intt_max_lux * dynamic_intt_min_unit)){
+#if ALS_DEBUG
+ LOG_INFO("[%s]:raw_convert_to_lux: change max lux\r\n", __func__);
+#endif
+ lux = dynamic_intt_max_lux * dynamic_intt_min_unit;
+ }
+ else if(lux <= (dynamic_intt_min_lux*dynamic_intt_min_unit)){
+#if ALS_DEBUG
+ LOG_INFO("[%s]:raw_convert_to_lux: change min lux\r\n", __func__);
+#endif
+ lux = dynamic_intt_min_lux * dynamic_intt_min_unit;
+ }
+
+ return lux;
+}
+#endif
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_get_als_value(struct epl_sensor_priv *obj, u16 als)
+{
+ int idx;
+ int invalid = 0;
+#if ALS_DYN_INTT
+ long now_lux=0, lux_tmp=0;
+ bool change_flag = false;
+#endif
+ switch(epl_sensor.als.report_type)
+ {
+ case CMC_BIT_RAW:
+ return als;
+ break;
+
+ case CMC_BIT_PRE_COUNT:
+ return (als * epl_sensor.als.factory.lux_per_count)/1000;
+ break;
+
+ case CMC_BIT_TABLE:
+ for(idx = 0; idx < obj->als_level_num; idx++)
+ {
+ if(als < als_level[idx])
+ {
+ break;
+ }
+ }
+
+ if(idx >= obj->als_value_num)
+ {
+ LOG_ERR("exceed range\n");
+ idx = obj->als_value_num - 1;
+ }
+
+ if(!invalid)
+ {
+ LOG_INFO("ALS: %05d => %05d\n", als, als_value[idx]);
+ return als_value[idx];
+ }
+ else
+ {
+ LOG_ERR("ALS: %05d => %05d (-1)\n", als, als_value[idx]);
+ return als;
+ }
+ break;
+#if ALS_DYN_INTT
+ case CMC_BIT_DYN_INT:
+
+ if(epl_sensor.als.lsrc_type != CMC_BIT_LSRC_NON)
+ {
+ long luxratio = 0;
+ epl_sensor_read_als_status(obj->client);
+
+ if (epl_sensor.als.data.channels[0] == 0)
+ {
+ epl_sensor.als.data.channels[0] = 1;
+ LOG_ERR("[%s]:read ch0 data is 0 \r\n", __func__);
+ }
+
+ luxratio = (long)((als*dynamic_intt_min_unit) / epl_sensor.als.data.channels[0]); //lux ratio (A=CH1/CH0)
+
+ obj->ratio = luxratio;
+ if((epl_sensor.als.saturation >> 5) == 0)
+ {
+ if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_SCALE || epl_sensor.als.lsrc_type == CMC_BIT_LSRC_BOTH)
+ {
+ if(obj->ratio == 0){
+ obj->last_ratio = luxratio;
+ }
+ else{
+ obj->last_ratio = (luxratio + obj->last_ratio*9) / 10;
+ }
+
+ if (obj->last_ratio >= obj->lsource_thd_high) //fluorescent (C1)
+ {
+ c_gain = obj->c_gain_h;
+ }
+ else if (obj->last_ratio <= obj->lsource_thd_low) //incandescent (C2)
+ {
+ c_gain = obj->c_gain_l;
+ }
+ else if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_BOTH)
+ {
+ int a = 0, b = 0, c = 0;
+ a = (obj->c_gain_h - obj->c_gain_l) * dynamic_intt_min_unit / (obj->lsource_thd_high - obj->lsource_thd_low);
+ b = (obj->c_gain_h) - ((a * obj->lsource_thd_high)/dynamic_intt_min_unit );
+ c = ((a * obj->last_ratio)/dynamic_intt_min_unit) + b;
+ if(c > obj->c_gain_h)
+ c_gain = obj->c_gain_h;
+ else if (c < obj->c_gain_l)
+ c_gain = obj->c_gain_l;
+ else
+ c_gain = c;
+ }
+ }
+ else if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_SLOPE)
+ {
+ if (luxratio >= obj->lsource_thd_high) //fluorescent (C1)
+ {
+ c_gain = obj->c_gain_h;
+ }
+ else if (luxratio <= obj->lsource_thd_low) //incandescent (C2)
+ {
+ c_gain = obj->c_gain_l;
+ }
+ else{ /*mix*/
+ int a = 0, b = 0, c = 0;
+ a = (obj->c_gain_h - obj->c_gain_l) * dynamic_intt_min_unit / (obj->lsource_thd_high - obj->lsource_thd_low);
+ b = (obj->c_gain_h) - ((a * obj->lsource_thd_high)/dynamic_intt_min_unit );
+ c = ((a * luxratio)/dynamic_intt_min_unit) + b;
+ if(c > obj->c_gain_h)
+ c_gain = obj->c_gain_h;
+ else if (c < obj->c_gain_l)
+ c_gain = obj->c_gain_l;
+ else
+ c_gain = c;
+ }
+ }
+ LOG_INFO("[%s]:ch0=%d, ch1=%d, c_gain=%d, obj->ratio=%d, obj->last_ratio=%d \r\n\n",
+ __func__,epl_sensor.als.data.channels[0], als, c_gain, obj->ratio, obj->last_ratio);
+ }
+ else
+ {
+ LOG_INFO("[%s]: ALS saturation(%d) \r\n", __func__, (epl_sensor.als.saturation >> 5));
+ }
+ }
+
+#if ALS_DEBUG
+ LOG_INFO("[%s]: dynamic_intt_idx=%d, als_dynamic_intt_value=%d, dynamic_intt_gain=%d, als=%d \r\n",
+ __func__, dynamic_intt_idx, als_dynamic_intt_value[dynamic_intt_idx], als_dynamic_intt_gain[dynamic_intt_idx], als);
+#endif
+
+ if(als > dynamic_intt_high_thr)
+ {
+ if(dynamic_intt_idx == (als_dynamic_intt_intt_num - 1)){
+ als = dynamic_intt_high_thr;
+ lux_tmp = raw_convert_to_lux(als);
+#if ALS_DEBUG
+ LOG_INFO(">>>>>>>>>>>>>>>>>>>>>>>> INTT_MAX_LUX\r\n");
+#endif
+ }
+ else{
+ change_flag = true;
+ als = dynamic_intt_high_thr;
+ lux_tmp = raw_convert_to_lux(als);
+ dynamic_intt_idx++;
+#if ALS_DEBUG
+ LOG_INFO(">>>>>>>>>>>>>>>>>>>>>>>>change INTT high: %d, raw: %d \r\n", dynamic_intt_idx, als);
+#endif
+ }
+ }
+ else if(als < dynamic_intt_low_thr)
+ {
+ if(dynamic_intt_idx == 0){
+ //als = dynamic_intt_low_thr;
+ lux_tmp = raw_convert_to_lux(als);
+#if ALS_DEBUG
+ LOG_INFO(">>>>>>>>>>>>>>>>>>>>>>>> INTT_MIN_LUX\r\n");
+#endif
+ }
+ else{
+ change_flag = true;
+ als = dynamic_intt_low_thr;
+ lux_tmp = raw_convert_to_lux(als);
+ dynamic_intt_idx--;
+#if ALS_DEBUG
+ LOG_INFO(">>>>>>>>>>>>>>>>>>>>>>>>change INTT low: %d, raw: %d \r\n", dynamic_intt_idx, als);
+#endif
+ }
+ }
+ else
+ {
+ lux_tmp = raw_convert_to_lux(als);
+ }
+
+ now_lux = lux_tmp;
+ dynamic_intt_lux = now_lux/dynamic_intt_min_unit;
+
+ epl_sensor_report_lux(dynamic_intt_lux);
+
+ if(change_flag == true)
+ {
+ epl_sensor.als.integration_time = als_dynamic_intt_intt[dynamic_intt_idx];
+ epl_sensor.als.gain = als_dynamic_intt_gain[dynamic_intt_idx];
+ dynamic_intt_high_thr = als_dynamic_intt_high_thr[dynamic_intt_idx];
+ dynamic_intt_low_thr = als_dynamic_intt_low_thr[dynamic_intt_idx];
+ epl_sensor_update_mode(obj->client);
+ change_flag = false;
+ }
+ return dynamic_intt_lux;
+
+ break;
+#endif
+
+ }
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+int epl_sensor_read_als(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = i2c_get_clientdata(client);
+
+ if(client == NULL)
+ {
+ LOG_ERR("CLIENT CANN'T EQUL NULL\n");
+ return -1;
+ }
+
+ epl_sensor_I2C_Read(epld->client, 0x13, 4);
+#if PS_DYN_K && PS_DYN_K_STR
+ if(dynk_enhance_flag == false)
+ {
+ dynk_enhance_ch0 = (gRawData.raw_bytes[1]<<8) | gRawData.raw_bytes[0];
+ dynk_enhance_ch1 = (gRawData.raw_bytes[3]<<8) | gRawData.raw_bytes[2];
+
+ LOG_INFO("read dynk_enhance_ch0 = %d\n", dynk_enhance_ch0);
+ LOG_INFO("read dynk_enhance_ch1 = %d\n", dynk_enhance_ch1);
+ }
+ else
+#endif
+ {
+ epl_sensor.als.data.channels[0] = (gRawData.raw_bytes[1]<<8) | gRawData.raw_bytes[0];
+ epl_sensor.als.data.channels[1] = (gRawData.raw_bytes[3]<<8) | gRawData.raw_bytes[2];
+
+#if ALS_DEBUG
+ LOG_INFO("read als channel 0 = %d\n", epl_sensor.als.data.channels[0]);
+ LOG_INFO("read als channel 1 = %d\n", epl_sensor.als.data.channels[1]);
+#endif
+ }
+
+
+ if(epl_sensor.wait == EPL_WAIT_SINGLE)
+ epl_sensor_I2C_Write(epld->client,0x11, epl_sensor.power | epl_sensor.reset);
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void epl_sensor_report_ps_status(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+
+ LOG_INFO("------------------- epl_sensor.ps.data.data=%d, value=%d \n\n", epl_sensor.ps.data.data, epl_sensor.ps.compare_low >> 3);
+
+ input_report_abs(epld->ps_input_dev, ABS_DISTANCE, epl_sensor.ps.compare_low >> 3);
+ input_sync(epld->ps_input_dev);
+}
+
+int epl_sensor_read_ps(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = i2c_get_clientdata(client);
+ if(client == NULL)
+ {
+ LOG_ERR("CLIENT CANN'T EQUL NULL\n");
+ return -1;
+ }
+
+ epl_sensor_I2C_Read(epld->client,0x1c, 4);
+
+ epl_sensor.ps.data.ir_data = (gRawData.raw_bytes[1]<<8) | gRawData.raw_bytes[0];
+ epl_sensor.ps.data.data = (gRawData.raw_bytes[3]<<8) | gRawData.raw_bytes[2];
+
+ LOG_INFO("[%s] data = %d\n", __FUNCTION__, epl_sensor.ps.data.data);
+ LOG_INFO("[%s] ir data = %d\n", __FUNCTION__, epl_sensor.ps.data.ir_data);
+
+ if(epl_sensor.wait == EPL_WAIT_SINGLE)
+ epl_sensor_I2C_Write(epld->client, 0x11, epl_sensor.power | epl_sensor.reset);
+
+ return 0;
+}
+
+int epl_sensor_read_ps_status(struct i2c_client *client)
+{
+ u8 buf;
+#if PS_GES
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ u8 new_ps_state;
+ u8 ges_saturation;
+ bool enable_ges = obj->enable_gflag==1 && obj->ges_suspend==0;
+#endif
+ if(client == NULL)
+ {
+ LOG_ERR("CLIENT CANN'T EQUL NULL\n");
+ return -1;
+ }
+
+ epl_sensor_I2C_Read(client, 0x1b, 1);
+
+ buf = gRawData.raw_bytes[0];
+
+#if PS_GES
+ ges_saturation = (buf & 0x20);
+ new_ps_state = (buf & 0x08) >> 3;
+ LOG_INFO("[%s]:new_ps_state=%d, ps_ges_suspend_flag=%d \r\n", __func__, new_ps_state, ps_ges_suspend_flag);
+ if(enable_ges == 1 && epl_sensor.ges.polling_mode == 1)
+ {
+ if( new_ps_state == 0 && (epl_sensor.ps.compare_low>>3 == 1) && ps_ges_suspend_flag == false && ges_saturation == 0)
+ epl_sensor_notify_event();
+ }
+ else if(enable_ges == 1 && epl_sensor.ges.polling_mode == 0 && ps_ges_suspend_flag == false && ges_saturation == 0)
+ {
+ if(new_ps_state == 0)
+ epl_sensor_notify_event();
+ }
+#endif
+
+ epl_sensor.ps.saturation = (buf & 0x20);
+ epl_sensor.ps.compare_high = (buf & 0x10);
+ epl_sensor.ps.compare_low = (buf & 0x08);
+ epl_sensor.ps.interrupt_flag = (buf & 0x04);
+ epl_sensor.ps.compare_reset = (buf & 0x02);
+ epl_sensor.ps.lock= (buf & 0x01);
+#if PS_DEBUG
+ LOG_INFO("ps: ~~~~ PS ~~~~~ \n");
+ LOG_INFO("ps: buf = 0x%x\n", buf);
+ LOG_INFO("ps: sat = 0x%x\n", epl_sensor.ps.saturation);
+ LOG_INFO("ps: cmp h = 0x%x, l = 0x%x\n", epl_sensor.ps.compare_high, epl_sensor.ps.compare_low);
+ LOG_INFO("ps: int_flag = 0x%x\n",epl_sensor.ps.interrupt_flag);
+ LOG_INFO("ps: cmp_rstn = 0x%x, lock = %x\n", epl_sensor.ps.compare_reset, epl_sensor.ps.lock);
+#endif
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int set_psensor_intr_threshold(uint16_t low_thd, uint16_t high_thd)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ struct i2c_client *client = epld->client;
+ uint8_t high_msb ,high_lsb, low_msb, low_lsb;
+
+
+ high_msb = (uint8_t) (high_thd >> 8);
+ high_lsb = (uint8_t) (high_thd & 0x00ff);
+ low_msb = (uint8_t) (low_thd >> 8);
+ low_lsb = (uint8_t) (low_thd & 0x00ff);
+
+ LOG_INFO("%s: low_thd = %d, high_thd = %d \n",__FUNCTION__, low_thd, high_thd);
+
+ epl_sensor_I2C_Write(client,0x0c,low_lsb);
+ epl_sensor_I2C_Write(client,0x0d,low_msb);
+ epl_sensor_I2C_Write(client,0x0e,high_lsb);
+ epl_sensor_I2C_Write(client,0x0f,high_msb);
+
+ return 0;
+}
+
+static int set_lsensor_intr_threshold(uint16_t low_thd, uint16_t high_thd)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ struct i2c_client *client = epld->client;
+ uint8_t high_msb ,high_lsb, low_msb, low_lsb;
+
+ high_msb = (uint8_t) (high_thd >> 8);
+ high_lsb = (uint8_t) (high_thd & 0x00ff);
+ low_msb = (uint8_t) (low_thd >> 8);
+ low_lsb = (uint8_t) (low_thd & 0x00ff);
+
+ epl_sensor_I2C_Write(client,0x08,low_lsb);
+ epl_sensor_I2C_Write(client,0x09,low_msb);
+ epl_sensor_I2C_Write(client,0x0a,high_lsb);
+ epl_sensor_I2C_Write(client,0x0b,high_msb);
+
+ LOG_INFO("%s: low_thd = %d, high_thd = %d \n",__FUNCTION__, low_thd, high_thd);
+
+ return 0;
+}
+
+int epl_sensor_read_als_status(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ u8 buf;
+
+ if(client == NULL)
+ {
+ LOG_ERR("CLIENT CANN'T EQUL NULL\n");
+ return -1;
+ }
+
+ epl_sensor_I2C_Read(epld->client, 0x12, 1);
+
+ buf = gRawData.raw_bytes[0];
+
+ epl_sensor.als.saturation = (buf & 0x20);
+ epl_sensor.als.compare_high = (buf & 0x10);
+ epl_sensor.als.compare_low = (buf & 0x08);
+ epl_sensor.als.interrupt_flag = (buf & 0x04);
+ epl_sensor.als.compare_reset = (buf & 0x02);
+ epl_sensor.als.lock= (buf & 0x01);
+#if ALS_DEBUG
+ LOG_INFO("als: ~~~~ ALS ~~~~~ \n");
+ LOG_INFO("als: buf = 0x%x\n", buf);
+ LOG_INFO("als: sat = 0x%x\n", epl_sensor.als.saturation);
+ LOG_INFO("als: cmp h = 0x%x, l = 0x%x\n", epl_sensor.als.compare_high, epl_sensor.als.compare_low);
+ LOG_INFO("als: int_flag = 0x%x\n",epl_sensor.als.interrupt_flag);
+ LOG_INFO("als: cmp_rstn = 0x%x, lock = 0x%x\n", epl_sensor.als.compare_reset, epl_sensor.als.lock);
+#endif
+ return 0;
+}
+
+static int write_factory_calibration(struct epl_sensor_priv *epl_data, char* ps_data, int ps_cal_len)
+{
+ struct file *fp_cal;
+
+ mm_segment_t fs;
+ loff_t pos;
+
+ LOG_FUN();
+ pos = 0;
+
+ fp_cal = filp_open(ps_cal_file, O_CREAT|O_RDWR|O_TRUNC, 0755/*S_IRWXU*/);
+ if (IS_ERR(fp_cal))
+ {
+ LOG_ERR("[ELAN]create file_h error\n");
+ return -1;
+ }
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ vfs_write(fp_cal, ps_data, ps_cal_len, &pos);
+
+ filp_close(fp_cal, NULL);
+
+ set_fs(fs);
+
+ return 0;
+}
+
+static bool read_factory_calibration(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ struct file *fp;
+ mm_segment_t fs;
+ loff_t pos;
+ char buffer[100]= {0};
+ if(epl_sensor.ps.factory.calibration_enable && !epl_sensor.ps.factory.calibrated)
+ {
+ fp = filp_open(ps_cal_file, O_RDWR, S_IRUSR);
+
+ if (IS_ERR(fp))
+ {
+ LOG_ERR("NO PS calibration file(%d)\n", (int)IS_ERR(fp));
+ epl_sensor.ps.factory.calibration_enable = false;
+ }
+ else
+ {
+ int ps_cancelation = 0, ps_hthr = 0, ps_lthr = 0;
+ pos = 0;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ vfs_read(fp, buffer, sizeof(buffer), &pos);
+ filp_close(fp, NULL);
+
+ sscanf(buffer, "%d,%d,%d", &ps_cancelation, &ps_hthr, &ps_lthr);
+ epl_sensor.ps.factory.cancelation = ps_cancelation;
+ epl_sensor.ps.factory.high_threshold = ps_hthr;
+ epl_sensor.ps.factory.low_threshold = ps_lthr;
+ set_fs(fs);
+
+ epl_sensor.ps.high_threshold = epl_sensor.ps.factory.high_threshold;
+ epl_sensor.ps.low_threshold = epl_sensor.ps.factory.low_threshold;
+ epl_sensor.ps.cancelation = epl_sensor.ps.factory.cancelation;
+ }
+
+ epl_sensor_I2C_Write(epld->client,0x22, (u8)(epl_sensor.ps.cancelation& 0xff));
+ epl_sensor_I2C_Write(epld->client,0x23, (u8)((epl_sensor.ps.cancelation & 0xff00) >> 8));
+ set_psensor_intr_threshold(epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+
+ epl_sensor.ps.factory.calibrated = true;
+ }
+
+ if(epl_sensor.als.factory.calibration_enable && !epl_sensor.als.factory.calibrated)
+ {
+ fp = filp_open(als_cal_file, O_RDONLY, S_IRUSR);
+ if (IS_ERR(fp))
+ {
+ LOG_ERR("NO ALS calibration file(%d)\n", (int)IS_ERR(fp));
+ epl_sensor.als.factory.calibration_enable = false;
+ }
+ else
+ {
+ int als_lux_per_count = 0;
+ pos = 0;
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ vfs_read(fp, buffer, sizeof(buffer), &pos);
+ filp_close(fp, NULL);
+
+ sscanf(buffer, "%d", &als_lux_per_count);
+ epl_sensor.als.factory.lux_per_count = als_lux_per_count;
+ set_fs(fs);
+ }
+ epl_sensor.als.factory.calibrated = true;
+ }
+ return true;
+}
+
+static int epl_run_ps_calibration(struct epl_sensor_priv *epl_data)
+{
+ struct epl_sensor_priv *epld = epl_data;
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ u16 ch1=0;
+ u32 ch1_all=0;
+ int count =5, i;
+ int ps_hthr=0, ps_lthr=0, ps_cancelation=0, ps_cal_len = 0;
+ char ps_calibration[20];
+
+
+ if(PS_MAX_XTALK < 0)
+ {
+ LOG_ERR("[%s]:Failed: PS_MAX_XTALK < 0 \r\n", __func__);
+ return -EINVAL;
+ }
+
+ if(enable_ps == 0)
+ {
+ epld->enable_pflag = 1;
+ epl_sensor_update_mode(epld->client);
+ }
+
+ polling_flag = false;
+
+ for(i=0; i<count; i++)
+ {
+ msleep(50);
+ switch(epl_sensor.mode)
+ {
+ case EPL_MODE_PS:
+ case EPL_MODE_ALS_PS:
+ if(enable_ps == true && polling_flag == true && eint_flag == true && epl_sensor.ps.polling_mode == 0)
+ epl_sensor_read_ps(epld->client);
+ ch1 = epl_sensor.ps.data.data;
+ break;
+ }
+
+ ch1_all = ch1_all + ch1;
+ if(epl_sensor.wait == EPL_WAIT_SINGLE)
+ epl_sensor_I2C_Write(epld->client,0x11, epl_sensor.power | epl_sensor.reset);
+ }
+
+
+ ch1 = (u16)(ch1_all/count);
+
+ if(ch1 > PS_MAX_XTALK)
+ {
+ LOG_ERR("[%s]:Failed: ch1 > max_xtalk(%d) \r\n", __func__, ch1);
+ return -EINVAL;
+ }
+ else if(ch1 <= 0)
+ {
+ LOG_ERR("[%s]:Failed: ch1 = 0\r\n", __func__);
+ return -EINVAL;
+ }
+
+ ps_hthr = ch1 + PS_h_offset;
+ ps_lthr = ch1 + PS_l_offset;
+
+ ps_cal_len = sprintf(ps_calibration, "%d,%d,%d", ps_cancelation, ps_hthr, ps_lthr);
+
+ if(write_factory_calibration(epld, ps_calibration, ps_cal_len) < 0)
+ {
+ LOG_ERR("[%s] create file error \n", __func__);
+ return -EINVAL;
+ }
+
+ epl_sensor.ps.low_threshold = ps_lthr;
+ epl_sensor.ps.high_threshold = ps_hthr;
+ set_psensor_intr_threshold(epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+
+ LOG_INFO("[%s]: ch1 = %d\n", __func__, ch1);
+
+ polling_flag = true;
+ epl_sensor_restart_polling();
+ return ch1;
+}
+
+/*
+//====================write global variable===============//
+*/
+static void write_global_variable(struct i2c_client *client)
+{
+ u8 buf;
+#if HS_ENABLE
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ bool enable_hs = obj->enable_hflag==1 && obj->hs_suspend==0;
+#endif
+#if PS_GES
+ bool enable_ges = obj->enable_gflag==1 && obj->ges_suspend==0;
+#endif
+ //wake up chip
+ buf = epl_sensor.reset | epl_sensor.power;
+ epl_sensor_I2C_Write(client,0x11, buf);
+
+ /* read revno*/
+ epl_sensor_I2C_Read(client, 0x20, 2);
+ epl_sensor.revno = gRawData.raw_bytes[0] | gRawData.raw_bytes[1] << 8;
+
+ /*chip refrash*/
+ epl_sensor_I2C_Write(client, 0xfd, 0x8e);
+ epl_sensor_I2C_Write(client, 0xfe, 0x22);
+ epl_sensor_I2C_Write(client, 0xfe, 0x02);
+ epl_sensor_I2C_Write(client, 0xfd, 0x00);
+
+ epl_sensor_I2C_Write(client, 0xfc, EPL_A_D | EPL_NORMAL| EPL_GFIN_ENABLE | EPL_VOS_ENABLE | EPL_DOC_ON);
+
+#if HS_ENABLE
+ if(enable_hs)
+ {
+ epl_sensor.mode = EPL_MODE_PS;
+ epl_sensor_I2C_Write(obj->client, 0x00, epl_sensor.wait | EPL_MODE_IDLE);
+
+ /*hs setting*/
+ buf = epl_sensor.hs.integration_time | epl_sensor.hs.gain;
+ epl_sensor_I2C_Write(client, 0x03, buf);
+
+ buf = epl_sensor.hs.adc | epl_sensor.hs.cycle;
+ epl_sensor_I2C_Write(client, 0x04, buf);
+
+ buf = epl_sensor.hs.ir_on_control | epl_sensor.hs.ir_mode | epl_sensor.hs.ir_driver;
+ epl_sensor_I2C_Write(client, 0x05, buf);
+
+ buf = epl_sensor.hs.compare_reset | epl_sensor.hs.lock;
+
+ epl_sensor_I2C_Write(client, 0x1b, buf);
+ }
+#if !PS_GES /*PS_GES*/
+ else
+#elif PS_GES
+ else if(enable_ges)
+#endif /*PS_GES*/
+#endif
+
+#if PS_GES
+
+#if !HS_ENABLE /*HS_ENABLE*/
+ if(enable_ges)
+#endif /*HS_ENABLE*/
+ {
+ /*ges setting*/
+ buf = epl_sensor.ges.integration_time | epl_sensor.ges.gain;
+ epl_sensor_I2C_Write(client, 0x03, buf);
+
+ buf = epl_sensor.ges.adc | epl_sensor.ges.cycle;
+ epl_sensor_I2C_Write(client, 0x04, buf);
+
+ buf = epl_sensor.ges.ir_on_control | epl_sensor.ges.ir_mode | epl_sensor.ges.ir_drive;
+ epl_sensor_I2C_Write(client, 0x05, buf);
+
+ buf = epl_sensor.interrupt_control | epl_sensor.ges.persist |epl_sensor.ges.interrupt_type;
+ epl_sensor_I2C_Write(client, 0x06, buf);
+
+ buf = epl_sensor.ges.compare_reset | epl_sensor.ges.lock;
+ epl_sensor_I2C_Write(client, 0x1b, buf);
+
+ epl_sensor_I2C_Write(client, 0x22, (u8)(epl_sensor.ges.cancelation& 0xff));
+ epl_sensor_I2C_Write(client, 0x23, (u8)((epl_sensor.ges.cancelation & 0xff00) >> 8));
+ set_psensor_intr_threshold(epl_sensor.ges.low_threshold, epl_sensor.ges.high_threshold);
+ }
+ else
+#endif
+ {
+ /*ps setting*/
+ buf = epl_sensor.ps.integration_time | epl_sensor.ps.gain;
+ epl_sensor_I2C_Write(client,0x03, buf);
+
+ buf = epl_sensor.ps.adc | epl_sensor.ps.cycle;
+ epl_sensor_I2C_Write(client,0x04, buf);
+
+ buf = epl_sensor.ps.ir_on_control | epl_sensor.ps.ir_mode | epl_sensor.ps.ir_drive;
+ epl_sensor_I2C_Write(client,0x05, buf);
+
+ buf = epl_sensor.interrupt_control | epl_sensor.ps.persist |epl_sensor.ps.interrupt_type;
+ epl_sensor_I2C_Write(client,0x06, buf);
+
+ buf = epl_sensor.ps.compare_reset | epl_sensor.ps.lock;
+ epl_sensor_I2C_Write(client,0x1b, buf);
+
+ epl_sensor_I2C_Write(client,0x22, (u8)(epl_sensor.ps.cancelation& 0xff));
+ epl_sensor_I2C_Write(client,0x23, (u8)((epl_sensor.ps.cancelation & 0xff0) >> 8));
+ set_psensor_intr_threshold(epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+
+ /*als setting*/
+ buf = epl_sensor.als.integration_time | epl_sensor.als.gain;
+ epl_sensor_I2C_Write(client,0x01, buf);
+
+ buf = epl_sensor.als.adc | epl_sensor.als.cycle;
+ epl_sensor_I2C_Write(client,0x02, buf);
+
+ buf = epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type;
+ epl_sensor_I2C_Write(client,0x07, buf);
+
+ buf = epl_sensor.als.compare_reset | epl_sensor.als.lock;
+ epl_sensor_I2C_Write(client,0x12, buf);
+
+ set_lsensor_intr_threshold(epl_sensor.als.low_threshold, epl_sensor.als.high_threshold);
+ }
+ //set mode and wait
+ buf = epl_sensor.wait | epl_sensor.mode;
+ epl_sensor_I2C_Write(client,0x00, buf);
+}
+
+static void set_als_ps_intr_type(struct i2c_client *client, bool ps_polling, bool als_polling)
+{
+
+ //set als / ps interrupt control mode and trigger type
+ switch((ps_polling << 1) | als_polling)
+ {
+ case 0: // ps and als interrupt
+ epl_sensor.interrupt_control = EPL_INT_CTRL_ALS_OR_PS;
+ epl_sensor.als.interrupt_type = EPL_INTTY_ACTIVE;
+ epl_sensor.ps.interrupt_type = EPL_INTTY_ACTIVE;
+ break;
+
+ case 1: //ps interrupt and als polling
+ epl_sensor.interrupt_control = EPL_INT_CTRL_PS;
+ epl_sensor.als.interrupt_type = EPL_INTTY_DISABLE;
+ epl_sensor.ps.interrupt_type = EPL_INTTY_ACTIVE;
+ break;
+
+ case 2: // ps polling and als interrupt
+ epl_sensor.interrupt_control = EPL_INT_CTRL_ALS;
+ epl_sensor.als.interrupt_type = EPL_INTTY_ACTIVE;
+ epl_sensor.ps.interrupt_type = EPL_INTTY_DISABLE;
+ break;
+
+ case 3: //ps and als polling
+ epl_sensor.interrupt_control = EPL_INT_CTRL_ALS_OR_PS;
+ epl_sensor.als.interrupt_type = EPL_INTTY_DISABLE;
+ epl_sensor.ps.interrupt_type = EPL_INTTY_DISABLE;
+ break;
+ }
+}
+
+//====================initial global variable===============//
+static void initial_global_variable(struct i2c_client *client, struct epl_sensor_priv *obj)
+{
+
+ //general setting
+ epl_sensor.power = EPL_POWER_ON;
+ epl_sensor.reset = EPL_RESETN_RUN;
+ epl_sensor.mode = EPL_MODE_IDLE;
+ epl_sensor.wait = EPL_WAIT_20_MS;
+ epl_sensor.osc_sel = EPL_OSC_SEL_1MHZ;
+
+ //als setting
+ epl_sensor.als.polling_mode = ALS_POLLING_MODE;
+ epl_sensor.als.integration_time = EPL_ALS_INTT_64;
+ epl_sensor.als.gain = EPL_GAIN_MID;
+ epl_sensor.als.adc = EPL_PSALS_ADC_13;
+ epl_sensor.als.cycle = EPL_CYCLE_16;
+ epl_sensor.als.interrupt_channel_select = EPL_ALS_INT_CHSEL_1;
+ epl_sensor.als.persist = EPL_PERIST_1;
+ epl_sensor.als.compare_reset = EPL_CMP_RESET;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor.als.report_type = CMC_BIT_RAW; //CMC_BIT_DYN_INT
+ epl_sensor.als.high_threshold = ALS_HIGH_THRESHOLD;
+ epl_sensor.als.low_threshold = ALS_LOW_THRESHOLD;
+ //als factory
+ epl_sensor.als.factory.calibration_enable = false;
+ epl_sensor.als.factory.calibrated = false;
+ epl_sensor.als.factory.lux_per_count = LUX_PER_COUNT;
+
+#if ALS_DYN_INTT
+
+ epl_sensor.als.lsrc_type = CMC_BIT_LSRC_NON;
+
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ dynamic_intt_idx = dynamic_intt_init_idx;
+ epl_sensor.als.integration_time = als_dynamic_intt_intt[dynamic_intt_idx];
+ epl_sensor.als.gain = als_dynamic_intt_gain[dynamic_intt_idx];
+ dynamic_intt_high_thr = als_dynamic_intt_high_thr[dynamic_intt_idx];
+ dynamic_intt_low_thr = als_dynamic_intt_low_thr[dynamic_intt_idx];
+ }
+
+ c_gain = 21000; // 21000/1000=21
+
+ obj->lsource_thd_high = 1900; //different light source boundary (N) (1.9)
+ obj->lsource_thd_low = 1500; //1.5
+ obj->c_gain_h = 21000; //fluorescent (C1) (21)
+ obj->c_gain_l = 15000; //incandescent (C2) (15)
+
+#endif
+ //ps setting
+ epl_sensor.ps.polling_mode = PS_POLLING_MODE;
+ epl_sensor.ps.integration_time = EPL_PS_INTT_80;
+ epl_sensor.ps.gain = EPL_GAIN_MID;
+#if PS_DYN_K
+ dynk_min_ps_raw_data = 0xffff; //min raw data
+ dynk_max_ir_data = 50000; //max ch0
+ dynk_low_offset = 500; //low thd offset
+ dynk_high_offset = 800; //high thd offset
+ dynk_change_thd_max = 30000; //change thd condition
+ dynk_thd_offset = 500; //change thd offset
+#if PS_DYN_K_STR
+ dynk_enhance_max_ch0 = 50000; //enhance max ch0
+ dynk_enhance_integration_time = EPL_ALS_INTT_64;
+ dynk_enhance_gain = EPL_GAIN_LOW;
+ dynk_enhance_adc = EPL_PSALS_ADC_12;
+#endif
+#endif
+ epl_sensor.ps.adc = EPL_PSALS_ADC_12;
+ epl_sensor.ps.cycle = EPL_CYCLE_32;
+ epl_sensor.ps.persist = EPL_PERIST_1;
+ epl_sensor.ps.ir_on_control = EPL_IR_ON_CTRL_ON;
+ epl_sensor.ps.ir_mode = EPL_IR_MODE_CURRENT;
+ epl_sensor.ps.ir_drive = EPL_IR_DRIVE_100;
+ epl_sensor.ps.compare_reset = EPL_CMP_RESET;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor.ps.high_threshold = PS_HIGH_THRESHOLD;
+ epl_sensor.ps.low_threshold = PS_LOW_THRESHOLD;
+ //ps factory
+ epl_sensor.ps.factory.calibration_enable = false;
+ epl_sensor.ps.factory.calibrated = false;
+ epl_sensor.ps.factory.cancelation= 0;
+
+#if HS_ENABLE
+ //hs setting
+ epl_sensor.hs.integration_time = EPL_PS_INTT_80;
+ epl_sensor.hs.integration_time_max = EPL_PS_INTT_272;
+ epl_sensor.hs.integration_time_min = EPL_PS_INTT_32;
+ epl_sensor.hs.gain = EPL_GAIN_LOW;
+ epl_sensor.hs.adc = EPL_PSALS_ADC_11;
+ epl_sensor.hs.cycle = EPL_CYCLE_4;
+ epl_sensor.hs.ir_on_control = EPL_IR_ON_CTRL_ON;
+ epl_sensor.hs.ir_mode = EPL_IR_MODE_CURRENT;
+ epl_sensor.hs.ir_driver = EPL_IR_DRIVE_200;
+ epl_sensor.hs.compare_reset = EPL_CMP_RESET;
+ epl_sensor.hs.lock = EPL_UN_LOCK;
+ epl_sensor.hs.low_threshold = 6400;
+ epl_sensor.hs.mid_threshold = 25600;
+ epl_sensor.hs.high_threshold = 60800;
+#endif
+
+#if PS_GES
+ //ps setting
+ epl_sensor.ges.polling_mode = PS_POLLING_MODE;
+ epl_sensor.ges.integration_time = EPL_PS_INTT_80;
+ epl_sensor.ges.gain = EPL_GAIN_LOW;
+ epl_sensor.ges.adc = EPL_PSALS_ADC_12;
+ epl_sensor.ges.cycle = EPL_CYCLE_2;
+ epl_sensor.ges.persist = EPL_PERIST_1;
+ epl_sensor.ges.ir_on_control = EPL_IR_ON_CTRL_ON;
+ epl_sensor.ges.ir_mode = EPL_IR_MODE_CURRENT;
+ epl_sensor.ges.ir_drive = EPL_IR_DRIVE_200;
+ epl_sensor.ges.compare_reset = EPL_CMP_RESET;
+ epl_sensor.ges.lock = EPL_UN_LOCK;
+ epl_sensor.ges.high_threshold = ges_threshold_high;
+ epl_sensor.ges.low_threshold = ges_threshold_low;
+#endif
+
+ set_als_ps_intr_type(client, epl_sensor.ps.polling_mode, epl_sensor.als.polling_mode);
+ //write setting to sensor
+ write_global_variable(client);
+}
+
+#if HS_ENABLE
+int epl_sensor_read_hs(struct i2c_client *client)
+{
+ u8 buf;
+
+ if(client == NULL)
+ {
+ LOG_ERR("CLIENT CANN'T EQUL NULL\n");
+ return -1;
+ }
+
+ mutex_lock(&hs_sensor_mutex);
+ epl_sensor_I2C_Read(client,0x1e, 2);
+ epl_sensor.hs.raw = (gRawData.raw_bytes[1]<<8) | gRawData.raw_bytes[0];
+ LOG_INFO("epl_sensor.hs.raw=%d \r\n", epl_sensor.hs.raw);
+ if(epl_sensor.hs.dynamic_intt == true && epl_sensor.hs.raw>epl_sensor.hs.high_threshold && epl_sensor.hs.integration_time > epl_sensor.hs.integration_time_min)
+ {
+ epl_sensor.hs.integration_time -= 4;
+ buf = epl_sensor.hs.integration_time | epl_sensor.hs.gain;
+ epl_sensor_I2C_Write(client, 0x03, buf);
+ }
+ else if(epl_sensor.hs.dynamic_intt == true && epl_sensor.hs.raw>epl_sensor.hs.low_threshold && epl_sensor.hs.raw <epl_sensor.hs.mid_threshold && epl_sensor.hs.integration_time < epl_sensor.hs.integration_time_max)
+ {
+ epl_sensor.hs.integration_time += 4;
+ buf = epl_sensor.hs.integration_time | epl_sensor.hs.gain;
+ epl_sensor_I2C_Write(client, 0x03, buf);
+ }
+
+ mutex_unlock(&hs_sensor_mutex);
+
+ if(epl_sensor.hs.raws_count<200)
+ {
+ epl_sensor.hs.raws[epl_sensor.hs.raws_count] = epl_sensor.hs.raw;
+ epl_sensor.hs.raws_count++;
+ }
+
+ return 0;
+}
+#endif
+
+#if PS_DYN_K
+void epl_sensor_reset_dynk_thd(u8 last_status, u8 now_status)
+{
+ if(last_status==0 && now_status==1)
+ {
+#if PS_DYN_K_STR
+ if( (epl_sensor.ps.saturation == 0) && (epl_sensor.ps.data.ir_data < dynk_max_ir_data) && (dynk_enhance_ch0 < dynk_enhance_max_ch0) )
+#else
+ if( (epl_sensor.ps.saturation == 0)&&(epl_sensor.ps.data.ir_data < dynk_max_ir_data) )
+#endif
+ {
+ dynk_min_ps_raw_data = epl_sensor.ps.data.data;
+ }
+
+ dynk_thd_low = dynk_min_ps_raw_data + dynk_low_offset;
+ dynk_thd_high = dynk_min_ps_raw_data + dynk_high_offset;
+
+ if(dynk_thd_low>65534)
+ dynk_thd_low = 65534;
+ if(dynk_thd_high>65535)
+ dynk_thd_high = 65535;
+#if PS_DEBUG
+ LOG_INFO("[%s]:restart dynk ps raw = %d, min = %d, ir_data = %d\n", __func__, epl_sensor.ps.data.data, dynk_min_ps_raw_data, epl_sensor.ps.data.ir_data);
+ LOG_INFO("[%s]:restart dynk thre_l = %ld, thre_h = %ld\n", __func__, (long)dynk_thd_low, (long)dynk_thd_high);
+#endif
+ eint_flag = false;
+ set_psensor_intr_threshold((u16)dynk_thd_low, (u16)dynk_thd_high);
+ eint_flag = true;
+ }
+ else if(last_status==1 && now_status==0)
+ {
+ dynk_change_flag = true;
+ }
+}
+#if PS_DYN_K_STR
+void epl_sensor_enhance_enable(struct i2c_client *client, bool enable)
+{
+ bool cmp_flag = false;
+ u8 buf, now_cmp_l;
+ int enh_time=0, ps_time=0, total_time=0;
+ ps_time = ps_sensing_time(epl_sensor.ps.integration_time, epl_sensor.ps.adc, epl_sensor.ps.cycle);
+
+
+ //mutex_lock(&sensor_mutex);
+ polling_flag = false;
+
+
+ epl_sensor_I2C_Read(client, 0x1b, 1);
+ buf = gRawData.raw_bytes[0];
+ epl_sensor.ps.compare_high = (buf & 0x10);
+ now_cmp_l = (buf & 0x08);
+
+ if(now_cmp_l != epl_sensor.ps.compare_low)
+ {
+ LOG_INFO("[%s]: buf=0x%x, now_cmp_l=0x%x, epl_sensor.ps.compare_low=0x%x \r\n", __func__, buf, now_cmp_l, epl_sensor.ps.compare_low);
+ //PS unlock and reset
+ epl_sensor.ps.compare_reset = EPL_CMP_RESET;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+
+ cmp_flag = true;
+ }
+
+ epl_sensor.ps.interrupt_flag = EPL_INT_CLEAR;
+ epl_sensor.als.interrupt_flag = EPL_INT_CLEAR;
+
+ epl_sensor_I2C_Write(client, 0x00, epl_sensor.wait | EPL_MODE_IDLE);
+
+ if(enable == true){
+ enh_time = als_sensing_time(dynk_enhance_integration_time, dynk_enhance_adc, epl_sensor.als.cycle) / 2;
+ epl_sensor_I2C_Write(client, 0x01, dynk_enhance_integration_time | dynk_enhance_gain);
+ epl_sensor_I2C_Write(client, 0x02, dynk_enhance_adc | epl_sensor.als.cycle);
+ epl_sensor_I2C_Write(client, 0xfc, EPL_A_D | EPL_NORMAL| EPL_GFIN_ENABLE | EPL_VOS_ENABLE | EPL_DOC_OFF);
+ }
+ else
+ {
+ enh_time = als_sensing_time(epl_sensor.als.integration_time, epl_sensor.als.adc, epl_sensor.als.cycle);
+ epl_sensor_I2C_Write(client, 0x01, epl_sensor.als.integration_time | epl_sensor.als.gain);
+ epl_sensor_I2C_Write(client, 0x02, epl_sensor.als.adc | epl_sensor.als.cycle);
+ epl_sensor_I2C_Write(client, 0xfc, EPL_A_D | EPL_NORMAL| EPL_GFIN_ENABLE | EPL_VOS_ENABLE | EPL_DOC_ON);
+ }
+
+ als_frame_time = enh_time;
+ ps_frame_time = ps_time;
+
+ epl_sensor_I2C_Write(client, 0x00, epl_sensor.wait | epl_sensor.mode);
+ if(cmp_flag == true)
+ {
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+
+ cmp_flag = false;
+ }
+ //mutex_unlock(&sensor_mutex);
+
+ total_time = ps_time+enh_time+wait_value[epl_sensor.wait>>4];
+ if((2*total_time) >= dynk_polling_delay)
+ {
+ dynk_polling_delay = 2*total_time+50;
+ LOG_INFO("[%s]: dynk_polling_delay=%d \r\n", __func__, dynk_polling_delay);
+ }
+
+ msleep(total_time);
+ LOG_INFO("[%s] PS+ALS(%dms)\r\n", __func__, total_time);
+
+ //mutex_lock(&sensor_mutex);
+ if(enable == true)
+ {
+ epl_sensor_read_als(client);
+ }
+
+ if(epl_sensor.ps.interrupt_flag == EPL_INT_TRIGGER)
+ {
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+ }
+ polling_flag = true;
+ //mutex_unlock(&sensor_mutex);
+
+}
+#endif
+
+void epl_sensor_restart_dynk_polling(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ cancel_delayed_work(&dynk_thd_polling_work);
+ queue_delayed_work(epld->epl_wq, &dynk_thd_polling_work,msecs_to_jiffies(dynk_polling_delay));
+}
+
+void epl_sensor_dynk_thd_polling_work(struct work_struct *work)
+{
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+
+ bool enable_ps = obj->enable_pflag==1 && obj->ps_suspend==0;
+#if PS_DEBUG
+ bool enable_als = obj->enable_lflag==1 && obj->als_suspend==0;
+ LOG_INFO("[%s]:als / ps enable: %d / %d\n", __func__,enable_als, enable_ps);
+#endif
+
+ if(enable_ps == true)
+ {
+#if PS_DYN_K_STR
+ dynk_enhance_flag = false;
+ if(polling_flag == true && eint_flag == true)
+ {
+ epl_sensor_enhance_enable(obj->client, true);
+ }
+#endif
+ if(polling_flag == true && eint_flag == true && epl_sensor.ps.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_ps_status(obj->client);
+ epl_sensor_read_ps(obj->client);
+ mutex_unlock(&sensor_mutex);
+ }
+#if PS_DYN_K_STR
+ if( (dynk_min_ps_raw_data > epl_sensor.ps.data.data)
+ && (epl_sensor.ps.saturation == 0)
+ && (epl_sensor.ps.data.ir_data < dynk_max_ir_data)
+ && (dynk_enhance_ch0 < dynk_enhance_max_ch0) )
+#else
+ if( (dynk_min_ps_raw_data > epl_sensor.ps.data.data)
+ && (epl_sensor.ps.saturation == 0)
+ && (epl_sensor.ps.data.ir_data < dynk_max_ir_data) )
+#endif
+ {
+ dynk_min_ps_raw_data = epl_sensor.ps.data.data;
+ dynk_thd_low = dynk_min_ps_raw_data + dynk_low_offset;
+ dynk_thd_high = dynk_min_ps_raw_data + dynk_high_offset;
+
+ if(dynk_thd_low>65534)
+ dynk_thd_low = 65534;
+ if(dynk_thd_high>65535)
+ dynk_thd_high = 65535;
+#if PS_DEBUG
+ LOG_INFO("[%s]:dyn ps raw = %d, min = %d, ir_data = %d\n", __func__, epl_sensor.ps.data.data, dynk_min_ps_raw_data, epl_sensor.ps.data.ir_data);
+#endif
+ eint_flag = false;
+ mutex_lock(&sensor_mutex);
+ set_psensor_intr_threshold((u16)dynk_thd_low, (u16)dynk_thd_high);
+ mutex_unlock(&sensor_mutex);
+ eint_flag = true;
+#if PS_DEBUG
+ LOG_INFO("[%s]:dyn k thre_l = %ld, thre_h = %ld\n", __func__, (long)dynk_thd_low, (long)dynk_thd_high);
+#endif
+ }
+ else if(dynk_change_flag==true && (epl_sensor.ps.data.data>dynk_change_thd_max) && ( (epl_sensor.ps.compare_low >> 3)==0 ))
+ {
+ dynk_change_flag = false;
+ dynk_thd_low += dynk_thd_offset;
+ dynk_thd_high += dynk_thd_offset;
+
+ if(dynk_thd_low>65534)
+ dynk_thd_low = 65534;
+ if(dynk_thd_high>65535)
+ dynk_thd_high = 65535;
+
+ eint_flag = false;
+ mutex_lock(&sensor_mutex);
+ set_psensor_intr_threshold((u16)dynk_thd_low, (u16)dynk_thd_high);
+ mutex_unlock(&sensor_mutex);
+ eint_flag = true;
+#if PS_DEBUG
+ LOG_INFO("[%s]: epl_sensor.ps.data.data=%d, L/H=%ld/%ld \r\n", __func__, epl_sensor.ps.data.data, (long)dynk_thd_low, (long)dynk_thd_high);
+#endif
+ }
+#if PS_DYN_K_STR
+ if(polling_flag == true && eint_flag == true)
+ {
+ epl_sensor_enhance_enable(obj->client, false);
+ }
+ dynk_enhance_flag = true;
+#endif
+ queue_delayed_work(obj->epl_wq, &dynk_thd_polling_work,msecs_to_jiffies(dynk_polling_delay));
+ }
+}
+#endif
+
+/************************************************************************/
+//for 3637
+static int als_sensing_time(int intt, int adc, int cycle)
+{
+ long sensing_us_time;
+ int sensing_ms_time;
+ int als_intt, als_adc, als_cycle;
+
+ als_intt = als_intt_value[intt>>2];
+ als_adc = adc_value[adc>>3];
+ als_cycle = cycle_value[cycle];
+#if COMMON_DEBUG
+ LOG_INFO("ALS: INTT=%d, ADC=%d, Cycle=%d \r\n", als_intt, als_adc, als_cycle);
+#endif
+
+ sensing_us_time = (als_intt + als_adc*2*2) * 2 * als_cycle;
+ sensing_ms_time = sensing_us_time / 1000;
+
+#if COMMON_DEBUG
+ LOG_INFO("[%s]: sensing=%d ms \r\n", __func__, sensing_ms_time);
+#endif
+ return (sensing_ms_time + 5);
+}
+
+static int ps_sensing_time(int intt, int adc, int cycle)
+{
+ long sensing_us_time;
+ int sensing_ms_time;
+ int ps_intt, ps_adc, ps_cycle;
+
+ ps_intt = ps_intt_value[intt>>2];
+ ps_adc = adc_value[adc>>3];
+ ps_cycle = cycle_value[cycle];
+#if COMMON_DEBUG
+ LOG_INFO("PS: INTT=%d, ADC=%d, Cycle=%d \r\n", ps_intt, ps_adc, ps_cycle);
+#endif
+
+ sensing_us_time = (ps_intt*3 + ps_adc*2*3) * ps_cycle;
+ sensing_ms_time = sensing_us_time / 1000;
+#if COMMON_DEBUG
+ LOG_INFO("[%s]: sensing=%d ms\r\n", __func__, sensing_ms_time);
+#endif
+
+
+ return (sensing_ms_time + 5);
+}
+
+static int epl_sensor_get_wait_time(int ps_time, int als_time)
+{
+ int wait_idx = 0;
+ int wait_time = 0;
+
+ wait_time = als_time - ps_time;
+ if(wait_time < 0){
+ wait_time = 0;
+ }
+#if COMMON_DEBUG
+ LOG_INFO("[%s]: wait_len = %d \r\n", __func__, wait_len);
+#endif
+ for(wait_idx = 0; wait_idx < wait_len; wait_idx++)
+ {
+ if(wait_time < wait_value[wait_idx])
+ {
+ break;
+ }
+ }
+ if(wait_idx >= wait_len){
+ wait_idx = wait_len - 1;
+ }
+
+#if COMMON_DEBUG
+ LOG_INFO("[%s]: wait_idx = %d, wait = %dms \r\n", __func__, wait_idx, wait_value[wait_idx]);
+#endif
+ return (wait_idx << 4);
+}
+/************************************************************************/
+
+void epl_sensor_update_mode(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int als_time = 0, ps_time = 0;
+
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+#endif
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+ polling_flag = false;
+ als_time = als_sensing_time(epl_sensor.als.integration_time, epl_sensor.als.adc, epl_sensor.als.cycle);
+ ps_time = ps_sensing_time(epl_sensor.ps.integration_time, epl_sensor.ps.adc, epl_sensor.ps.cycle);
+
+ als_frame_time = als_time;
+ ps_frame_time = ps_time;
+
+#if HS_ENABLE
+ if(enable_hs)
+ {
+ LOG_INFO("[%s]: HS mode \r\n", __func__);
+ epl_sensor_restart_polling();
+ }
+ else
+#endif
+ {
+ //PS unlock and reset
+ epl_sensor.ps.compare_reset = EPL_CMP_RESET;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+
+ //ALS unlock and reset
+ epl_sensor.als.compare_reset = EPL_CMP_RESET;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+
+
+ //epl_sensor_I2C_Write(epld->client, 0x11, EPL_RESETN_RESET | EPL_POWER_OFF);
+ epl_sensor.ps.interrupt_flag = EPL_INT_CLEAR;
+ epl_sensor.als.interrupt_flag = EPL_INT_CLEAR;
+
+#if PS_GES
+ LOG_INFO("mode selection =0x%x\n", (enable_ps|enable_ges) | (enable_als << 1));
+#else
+ LOG_INFO("mode selection =0x%x\n", enable_ps | (enable_als << 1));
+#endif
+
+#if PS_GES
+ //**** mode selection ****
+ switch((enable_als << 1) | (enable_ps|enable_ges))
+#else
+ //**** mode selection ****
+ switch((enable_als << 1) | enable_ps)
+#endif
+ {
+ case 0: //disable all
+ epl_sensor.mode = EPL_MODE_IDLE;
+ break;
+
+ case 1: //als = 0, ps = 1
+#if PS_DYN_K && PS_DYN_K_STR
+ epl_sensor.mode = EPL_MODE_ALS_PS;
+#else
+ epl_sensor.mode = EPL_MODE_PS;
+#endif
+ break;
+
+ case 2: //als = 1, ps = 0
+ epl_sensor.mode = EPL_MODE_ALS;
+ break;
+
+ case 3: //als = 1, ps = 1
+ epl_sensor.mode = EPL_MODE_ALS_PS;
+ break;
+ }
+
+ //**** write setting ****
+ // step 1. set sensor at idle mode
+ // step 2. set sensor at operation mode
+ // step 3. delay sensing time
+ // step 4. unlock and run als / ps status
+ epl_sensor_I2C_Write(epld->client, 0x00, epl_sensor.wait | EPL_MODE_IDLE);
+ // initial factory calibration variable
+ read_factory_calibration();
+
+ epl_sensor_I2C_Write(epld->client, 0x02, epl_sensor.als.adc | epl_sensor.als.cycle);
+ set_als_ps_intr_type(epld->client, epl_sensor.ps.polling_mode, epl_sensor.als.polling_mode);
+
+ epl_sensor_I2C_Write(epld->client, 0x06, epl_sensor.interrupt_control | epl_sensor.ps.persist |epl_sensor.ps.interrupt_type);
+
+ epl_sensor_I2C_Write(epld->client, 0x07, epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type);
+
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT){
+ epl_sensor_I2C_Write(client, 0x01, epl_sensor.als.integration_time | epl_sensor.als.gain);
+ }
+#endif
+
+ if(epl_sensor.mode == EPL_MODE_ALS_PS && epl_sensor.als.polling_mode == 0 && epl_sensor.ps.polling_mode == 0){
+ int wait = 0;
+ wait = epl_sensor_get_wait_time(ps_time, als_time);
+ epl_sensor_I2C_Write(epld->client, 0x00, wait | epl_sensor.mode);
+ }
+ else{
+#if PS_GES
+ if(enable_ges == 1 && enable_ps == 0)
+ {
+ set_psensor_intr_threshold(epl_sensor.ges.low_threshold, epl_sensor.ges.high_threshold);
+ epl_sensor_I2C_Write(client, 0x00, EPL_WAIT_2_MS | epl_sensor.mode);
+ }
+ else
+#endif
+ epl_sensor_I2C_Write(epld->client, 0x00, epl_sensor.wait | epl_sensor.mode);
+ }
+
+ //ALS unlock and run
+ epl_sensor.als.compare_reset = EPL_CMP_RUN;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+
+ //epl_sensor_I2C_Write(epld->client, 0x11, epl_sensor.reset | epl_sensor.power);
+
+#if COMMON_DEBUG
+ //**** check setting ****
+ if(enable_ps == 1)
+ {
+ LOG_INFO("[%s] PS:low_thd = %d, high_thd = %d \n",__func__, epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+ }
+
+ if(enable_als == 1 && epl_sensor.als.polling_mode == 0)
+ {
+ LOG_INFO("[%s] ALS:low_thd = %d, high_thd = %d \n",__func__, epl_sensor.als.low_threshold, epl_sensor.als.high_threshold);
+ }
+#if PS_GES
+ if(enable_ges)
+ {
+ LOG_INFO("[%s] GES:low_thd = %d, high_thd = %d \n",__func__, epl_sensor.ges.low_threshold, epl_sensor.ges.high_threshold);
+
+ }
+#endif
+
+ LOG_INFO("[%s] reg0x00= 0x%x \n", __func__, epl_sensor.wait | epl_sensor.mode);
+ LOG_INFO("[%s] reg0x07= 0x%x \n", __func__, epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type);
+ LOG_INFO("[%s] reg0x06= 0x%x \n", __func__, epl_sensor.interrupt_control | epl_sensor.ps.persist |epl_sensor.ps.interrupt_type);
+ LOG_INFO("[%s] reg0x11= 0x%x \n", __func__, epl_sensor.power | epl_sensor.reset);
+ LOG_INFO("[%s] reg0x12= 0x%x \n", __func__, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ LOG_INFO("[%s] reg0x1b= 0x%x \n", __func__, epl_sensor.ps.compare_reset | epl_sensor.ps.lock);
+#endif
+
+ if(epl_sensor.mode == EPL_MODE_PS)
+ {
+ msleep(ps_time);
+ LOG_INFO("[%s] PS only(%dms)\r\n", __func__, ps_time);
+ }
+ else if (epl_sensor.mode == EPL_MODE_ALS)
+ {
+ msleep(als_time);
+ LOG_INFO("[%s] ALS only(%dms)\r\n", __func__, als_time);
+ }
+ else if (epl_sensor.mode == EPL_MODE_ALS_PS)
+ {
+ msleep(ps_time+als_time+wait_value[epl_sensor.wait>>4]);
+ LOG_INFO("[%s] PS+ALS(%dms)\r\n", __func__, ps_time+als_time+wait_value[epl_sensor.wait>>4]);
+ }
+
+ if(epl_sensor.ps.interrupt_flag == EPL_INT_TRIGGER)
+ {
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+ }
+
+ if(epl_sensor.als.interrupt_flag == EPL_INT_TRIGGER)
+ {
+ //ALS unlock and run
+ epl_sensor.als.compare_reset = EPL_CMP_RUN;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client, 0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ }
+
+#if PS_GES
+ if((enable_als==1 && epl_sensor.als.polling_mode==1) || (enable_ps==1 && epl_sensor.ps.polling_mode==1) || (enable_ges == 1 && epl_sensor.ges.polling_mode==1))
+#else
+ if((enable_als==1 && epl_sensor.als.polling_mode==1) || (enable_ps==1 && epl_sensor.ps.polling_mode==1))
+#endif
+ {
+ epl_sensor_restart_polling();
+ }
+
+#if PS_DYN_K
+ if(enable_ps == 1)
+ {
+ epl_sensor_restart_dynk_polling();
+ }
+#endif
+ }
+ polling_flag = true;
+
+}
+
+/*----------------------------------------------------------------------------*/
+static void epl_sensor_polling_work(struct work_struct *work)
+{
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ struct i2c_client *client = epld->client;
+
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+
+#endif
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+
+#if COMMON_DEBUG
+#if HS_ENABLE && PS_GES
+ LOG_INFO("enable_pflag=%d, enable_lflag=%d, enable_hs=%d, enable_ges=%d \n", enable_ps, enable_als, enable_hs, enable_ges);
+#elif HS_ENABLE
+ LOG_INFO("enable_pflag=%d, enable_lflag=%d, enable_hs=%d\n", enable_ps, enable_als, enable_hs);
+#elif PS_GES
+ LOG_INFO("enable_pflag=%d, enable_lflag=%d, enable_ges=%d\n", enable_ps, enable_als, enable_ges);
+#else
+ LOG_INFO("enable_pflag = %d, enable_lflag = %d \n", enable_ps, enable_als);
+#endif
+#endif
+
+#if PS_DYN_K && PS_DYN_K_STR
+ if(polling_flag == false && eint_flag == false && dynk_enhance_flag == false)
+#else
+ if(polling_flag == false && eint_flag == false)
+#endif
+ {
+#if PS_DYN_K && PS_DYN_K_STR
+ LOG_INFO("[%s]: epl_sensor_update_mode(%d) or eint_work(%d) is running, dynk_enhance_flag=%d !\r\n", __func__, polling_flag, eint_flag, dynk_enhance_flag);
+#else
+ LOG_INFO("[%s]: epl_sensor_update_mode(%d) or eint_work(%d) is running !\r\n", __func__, polling_flag, eint_flag);
+#endif
+ return;
+ }
+
+ cancel_delayed_work(&polling_work);
+
+ if( (enable_als && epl_sensor.als.polling_mode == 1) || (enable_ps && epl_sensor.ps.polling_mode == 1) )
+ {
+ queue_delayed_work(epld->epl_wq, &polling_work,msecs_to_jiffies(polling_time));
+ }
+
+#if HS_ENABLE
+ if (enable_hs)
+ {
+ queue_delayed_work(epld->epl_wq, &polling_work,msecs_to_jiffies(20));
+ epl_sensor_read_hs(client);
+ }
+#if PS_GES /*PS_GES*/
+ else if (enable_ges && epl_sensor.ges.polling_mode==1)
+#endif /*PS_GES*/
+#endif
+
+#if PS_GES
+#if !HS_ENABLE /*HS_ENABLE*/
+ if (enable_ges && epl_sensor.ges.polling_mode==1)
+#endif /*HS_ENABLE*/
+ {
+ queue_delayed_work(epld->epl_wq, &polling_work, msecs_to_jiffies(polling_time));
+ epl_sensor_read_ps(epld->client);
+ epl_sensor_read_ps_status(epld->client);
+ }
+#endif
+
+ if(enable_als && epl_sensor.als.polling_mode == 1)
+ {
+ int report_lux = 0;
+#if PS_DYN_K && PS_DYN_K_STR
+ if(polling_flag == true && eint_flag == true && dynk_enhance_flag == true)
+#else
+ if(polling_flag == true && eint_flag == true)
+#endif
+ {
+ mutex_lock(&sensor_mutex);
+ //epl_sensor_read_als_status(client); // for test
+ epl_sensor_read_als(client);
+ mutex_unlock(&sensor_mutex);
+ report_lux = epl_sensor_get_als_value(epld, epl_sensor.als.data.channels[1]);
+ if(epl_sensor.als.report_type != CMC_BIT_DYN_INT){
+ epl_sensor_report_lux(report_lux);
+ }
+ }
+ }
+
+ if(enable_ps && epl_sensor.ps.polling_mode == 1)
+ {
+#if PS_DYN_K && PS_DYN_K_STR
+ if(polling_flag == true && eint_flag == true && dynk_enhance_flag == true)
+#else
+ if(polling_flag == true && eint_flag == true)
+#endif
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_ps_status(client);
+ epl_sensor_read_ps(client);
+ mutex_unlock(&sensor_mutex);
+#if PS_DYN_K
+ epl_sensor_reset_dynk_thd(dynk_last_status, (epl_sensor.ps.compare_low >> 3));
+ dynk_last_status = (epl_sensor.ps.compare_low >> 3);
+#endif
+ epl_sensor_report_ps_status();
+ }
+ }
+#if HS_ENABLE && PS_GES
+ if(enable_als==false && enable_ps==false && enable_hs==false && enable_ges==false)
+#elif HS_ENABLE
+ if(enable_als==false && enable_ps==false && enable_hs==false)
+#elif PS_GES
+ if(enable_als==false && enable_ps==false && enable_ges==false)
+#else
+ if(enable_als==false && enable_ps==false)
+#endif
+ {
+ cancel_delayed_work(&polling_work);
+ LOG_INFO("disable sensor\n");
+ }
+
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static irqreturn_t epl_sensor_eint_func(int irqNo, void *handle)
+{
+ struct epl_sensor_priv *epld = (struct epl_sensor_priv*)handle;
+ disable_irq_nosync(epld->irq);
+ //queue_work(epld->epl_wq, &epl_sensor_irq_work);
+ schedule_delayed_work(&epld->eint_work, 0);
+
+ return IRQ_HANDLED;
+}
+/*----------------------------------------------------------------------------*/
+static void epl_sensor_intr_als_report_lux(void)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+
+ int report_lux = 0;
+ epl_sensor_read_als(epld->client);
+
+ report_lux = epl_sensor_get_als_value(epld, epl_sensor.als.data.channels[1]);
+ epl_sensor_report_lux(report_lux);
+
+ epl_sensor.als.compare_reset = EPL_CMP_RESET;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+
+ //set dynamic threshold
+ if(epl_sensor.als.compare_high >> 4)
+ {
+ epl_sensor.als.high_threshold = epl_sensor.als.high_threshold + 250;
+ epl_sensor.als.low_threshold = epl_sensor.als.low_threshold + 250;
+
+ if (epl_sensor.als.high_threshold > 60000)
+ {
+ epl_sensor.als.high_threshold = epl_sensor.als.high_threshold -250;
+ epl_sensor.als.low_threshold = epl_sensor.als.low_threshold - 250;
+ }
+ }
+ if(epl_sensor.als.compare_low>> 3)
+ {
+ epl_sensor.als.high_threshold = epl_sensor.als.high_threshold -250;
+ epl_sensor.als.low_threshold = epl_sensor.als.low_threshold - 250;
+
+ if (epl_sensor.als.high_threshold < 250)
+ {
+ epl_sensor.als.high_threshold = epl_sensor.als.high_threshold + 250;
+ epl_sensor.als.low_threshold = epl_sensor.als.low_threshold + 250;
+ }
+ }
+
+ if(epl_sensor.als.high_threshold < epl_sensor.als.low_threshold)
+ {
+ LOG_INFO("[%s]:recover default setting \r\n", __FUNCTION__);
+ epl_sensor.als.high_threshold = ALS_HIGH_THRESHOLD;
+ epl_sensor.als.low_threshold = ALS_LOW_THRESHOLD;
+ }
+
+ //write new threshold
+ set_lsensor_intr_threshold(epl_sensor.als.low_threshold, epl_sensor.als.high_threshold);
+}
+/*----------------------------------------------------------------------------*/
+static void epl_sensor_eint_work(struct work_struct *work)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+ eint_flag = false;
+ mutex_lock(&sensor_mutex);
+
+#if PS_GES
+ if(enable_ges && epl_sensor.ges.polling_mode == 0)
+ {
+ epl_sensor_read_ps_status(epld->client);
+ if(polling_flag == true)
+ {
+ //GES unlock and run
+ epl_sensor.ges.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ges.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x1b, epl_sensor.ges.compare_reset | epl_sensor.ges.lock);
+ }
+ }
+#endif
+ if(enable_ps && epl_sensor.ps.polling_mode == 0)
+ {
+ epl_sensor_read_ps_status(epld->client);
+ if(epl_sensor.ps.interrupt_flag == EPL_INT_TRIGGER)
+ {
+#if PS_DEBUG || PS_DYN_K
+ epl_sensor_read_ps(epld->client);
+#endif
+
+#if PS_DYN_K
+ epl_sensor_reset_dynk_thd(dynk_last_status, (epl_sensor.ps.compare_low >> 3));
+ dynk_last_status = (epl_sensor.ps.compare_low >> 3);
+#endif
+ epl_sensor_report_ps_status();
+
+ if(polling_flag == true)
+ {
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+ }
+
+ }
+ }
+ if(enable_als && epl_sensor.als.polling_mode == 0)
+ {
+ epl_sensor_read_als_status(epld->client);
+ if(epl_sensor.als.interrupt_flag == EPL_INT_TRIGGER)
+ {
+ epl_sensor_intr_als_report_lux();
+ if(polling_flag == true)
+ {
+ //ALS unlock and run
+ epl_sensor.als.compare_reset = EPL_CMP_RUN;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ }
+ }
+ }
+
+ //enable_irq(epld->irq);
+ mutex_unlock(&sensor_mutex);
+ eint_flag = true;
+ enable_irq(epld->irq);
+}
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_setup_interrupt(struct epl_sensor_priv *epld)
+{
+ struct i2c_client *client = epld->client;
+ int err = 0;
+#if QCOM
+ unsigned int irq_gpio;
+ unsigned int irq_gpio_flags;
+ struct device_node *np = client->dev.of_node;
+#endif
+ msleep(5);
+#if S5PV210
+ err = gpio_request(S5PV210_GPH0(1), "Elan EPL IRQ");
+ if (err)
+ {
+ LOG_ERR("gpio pin request fail (%d)\n", err);
+ goto initial_fail;
+ }
+ else
+ {
+ LOG_INFO("----- Samsung gpio config success -----\n");
+ s3c_gpio_cfgpin(S5PV210_GPH0(1),S3C_GPIO_SFN(0x0F)/*(S5PV210_GPH0_1_EXT_INT30_1) */);
+ s3c_gpio_setpull(S5PV210_GPH0(1),S3C_GPIO_PULL_UP);
+
+ }
+#elif SPREAD
+ //epld->intr_pin = ELAN_INT_PIN; /*need setting*/
+ err = gpio_request(epld->intr_pin, "Elan EPL IRQ");
+ if (err)
+ {
+ LOG_ERR("gpio pin request fail (%d)\n", err);
+ goto initial_fail;
+ }else{
+ gpio_direction_input(epld->intr_pin);
+ /*get irq*/
+ client->irq = gpio_to_irq(epld->intr_pin);
+ epld->irq = client->irq;
+ LOG_INFO("IRQ number is %d\n", client->irq);
+ }
+#elif QCOM
+ irq_gpio = of_get_named_gpio_flags(np, "epl,irq-gpio", 0, &irq_gpio_flags);
+ //irq_gpio = ELAN_INT_PIN;
+ epld->intr_pin = irq_gpio;
+ if (epld->intr_pin < 0) {
+ goto initial_fail;
+ }
+
+ if (gpio_is_valid(epld->intr_pin)) {
+ err = gpio_request(epld->intr_pin, "epl_irq_gpio");
+ if (err) {
+ LOG_ERR( "irq gpio request failed");
+ goto initial_fail;
+ }
+
+ err = gpio_direction_input(epld->intr_pin);
+ if (err) {
+ LOG_ERR("set_direction for irq gpio failed\n");
+ goto initial_fail;
+ }
+ }
+#elif LEADCORE
+ //epld->intr_pin = ELAN_INT_PIN; /*need setting*/
+ epld->intr_pin = irq_to_gpio(client->irq); /*need confirm*/
+
+ err = gpio_request(epld->intr_pin, "epl irq"); /*ep12182 irq*/
+ //err = gpio_request(epld->intr_pin, "ep12182 irq");
+ if (err < 0){
+ LOG_ERR("%s:Gpio request failed! \r\n", __func__);
+ goto initial_fail;
+ }
+ gpio_direction_input(epld->intr_pin);
+ client->irq = gpio_to_irq(epld->intr_pin);
+#elif MARVELL
+
+ epld->intr_pin = ELAN_INT_PIN; /*need setting*/
+ if(client->irq <= 0)
+ {
+ LOG_ERR("client->irq(%d) Failed \r\n", client->irq);
+ goto initial_fail;
+ }
+#endif
+ err = request_irq(epld->irq,epl_sensor_eint_func, IRQF_TRIGGER_FALLING,
+ "epl2182_pls", epld);
+ if(err <0)
+ {
+ LOG_ERR("request irq pin %d fail for gpio\n",err);
+ goto fail_free_intr_pin;
+ }
+
+ return err;
+
+initial_fail:
+fail_free_intr_pin:
+ gpio_free(epld->intr_pin);
+ //free_irq(epld->irq, epld);
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+
+static ssize_t epl_sensor_show_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+
+ ssize_t len = 0;
+ struct i2c_client *client = epl_sensor_obj->client;
+
+ if(!epl_sensor_obj)
+ {
+ LOG_ERR("epl_obj is null!!\n");
+ return 0;
+ }
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x00 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x00));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x01 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x01));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x02 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x02));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x03 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x03));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x04 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x04));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x05 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x05));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x06 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x06));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x07 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x07));
+ if(epl_sensor.als.polling_mode == 0)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x08 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x08));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x09 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x09));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0A value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0A));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0B value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0B));
+ }
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0C value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0C));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0D value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0D));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0E value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0E));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x0F value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x0F));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x11 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x11));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x12 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x12));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x1B value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x1B));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x22 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x22));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x23 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x23));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x24 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x24));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0x25 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x25));
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip id REG 0xFC value = 0x%x\n", i2c_smbus_read_byte_data(client, 0xFC));
+
+ return len;
+
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_show_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+#endif
+
+ if(!epl_sensor_obj)
+ {
+ LOG_ERR("epl_sensor_obj is null!!\n");
+ return 0;
+ }
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "chip is %s, ver is %s \n", EPL_DEV_NAME, DRIVER_VERSION);
+ len += snprintf(buf+len, PAGE_SIZE-len, "als/ps polling is %d-%d\n", epl_sensor.als.polling_mode, epl_sensor.ps.polling_mode);
+ len += snprintf(buf+len, PAGE_SIZE-len, "wait = %d, mode = %d\n",epl_sensor.wait >> 4, epl_sensor.mode);
+ len += snprintf(buf+len, PAGE_SIZE-len, "interrupt control = %d\n", epl_sensor.interrupt_control >> 4);
+ len += snprintf(buf+len, PAGE_SIZE-len, "frame time ps=%dms, als=%dms\n", ps_frame_time, als_frame_time);
+#if HS_ENABLE
+ if(enable_hs)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "hs adc= %d\n", epl_sensor.hs.adc>>3);
+ len += snprintf(buf+len, PAGE_SIZE-len, "hs int_time= %d\n", epl_sensor.hs.integration_time>>2);
+ len += snprintf(buf+len, PAGE_SIZE-len, "hs cycle= %d\n", epl_sensor.hs.cycle);
+ len += snprintf(buf+len, PAGE_SIZE-len, "hs gain= %d\n", epl_sensor.hs.gain);
+ len += snprintf(buf+len, PAGE_SIZE-len, "hs ch1 raw= %d\n", epl_sensor.hs.raw);
+ }
+#endif
+ if(enable_ps)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "PS: \n");
+ len += snprintf(buf+len, PAGE_SIZE-len, "INTEG = %d, gain = %d\n", epl_sensor.ps.integration_time >> 2, epl_sensor.ps.gain);
+ len += snprintf(buf+len, PAGE_SIZE-len, "ADC = %d, cycle = %d, ir drive = %d\n", epl_sensor.ps.adc >> 3, epl_sensor.ps.cycle, epl_sensor.ps.ir_drive);
+ len += snprintf(buf+len, PAGE_SIZE-len, "saturation = %d, int flag = %d\n", epl_sensor.ps.saturation >> 5, epl_sensor.ps.interrupt_flag >> 2);
+ len += snprintf(buf+len, PAGE_SIZE-len, "Thr(L/H) = (%d/%d)\n", epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+#if PS_DYN_K
+#if PS_DYN_K_STR
+ len += snprintf(buf+len, PAGE_SIZE-len, "Dyn enhance ch0 = %d \n", dynk_enhance_ch0);
+#endif
+ len += snprintf(buf+len, PAGE_SIZE-len, "Dyn thr(L/H) = (%ld/%ld)\n", (long)dynk_thd_low, (long)dynk_thd_high);
+#endif
+ len += snprintf(buf+len, PAGE_SIZE-len, "pals data = %d, data = %d\n", epl_sensor.ps.data.ir_data, epl_sensor.ps.data.data);
+ }
+ if(enable_als)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "ALS: \n");
+ len += snprintf(buf+len, PAGE_SIZE-len, "INTEG = %d, gain = %d\n", epl_sensor.als.integration_time >> 2, epl_sensor.als.gain);
+ len += snprintf(buf+len, PAGE_SIZE-len, "ADC = %d, cycle = %d\n", epl_sensor.als.adc >> 3, epl_sensor.als.cycle);
+#if ALS_DYN_INTT
+ if(epl_sensor.als.lsrc_type != CMC_BIT_LSRC_NON)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "lsource_thd_low=%d, lsource_thd_high=%d \n", epld->lsource_thd_low, epld->lsource_thd_high);
+ len += snprintf(buf+len, PAGE_SIZE-len, "saturation = %d\n", epl_sensor.als.saturation >> 5);
+
+ if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_SCALE || epl_sensor.als.lsrc_type == CMC_BIT_LSRC_BOTH)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "real_ratio = %d\n", epld->ratio);
+ len += snprintf(buf+len, PAGE_SIZE-len, "use_ratio = %d\n", epld->last_ratio);
+ }
+ else if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_SLOPE)
+ {
+ len += snprintf(buf+len, PAGE_SIZE-len, "ratio = %d\n", epld->ratio);
+ }
+ }
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "c_gain = %d\n", c_gain);
+ len += snprintf(buf+len, PAGE_SIZE-len, "dynamic_intt_lux = %d\n", dynamic_intt_lux);
+#endif
+ if(epl_sensor.als.polling_mode == 0)
+ len += snprintf(buf+len, PAGE_SIZE-len, "Thr(L/H) = (%d/%d)\n", epl_sensor.als.low_threshold, epl_sensor.als.high_threshold);
+ len += snprintf(buf+len, PAGE_SIZE-len, "ch0 = %d, ch1 = %d\n", epl_sensor.als.data.channels[0], epl_sensor.als.data.channels[1]);
+ }
+
+ return len;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_als_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint16_t mode=0;
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+
+ sscanf(buf, "%hu",&mode);
+ if(epld->enable_lflag != mode)
+ {
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ dynamic_intt_idx = dynamic_intt_init_idx;
+ epl_sensor.als.integration_time = als_dynamic_intt_intt[dynamic_intt_idx];
+ epl_sensor.als.gain = als_dynamic_intt_gain[dynamic_intt_idx];
+ dynamic_intt_high_thr = als_dynamic_intt_high_thr[dynamic_intt_idx];
+ dynamic_intt_low_thr = als_dynamic_intt_low_thr[dynamic_intt_idx];
+ }
+#endif
+ epld->enable_lflag = mode;
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_ps_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint16_t mode=0;
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+#endif
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+ LOG_FUN();
+
+ sscanf(buf, "%hu",&mode);
+#if HS_ENABLE
+ if(enable_hs == 1 && mode == 1)
+ {
+ epld->enable_hflag = 0;
+ if(hs_enable_flag == true)
+ {
+ epld->enable_lflag = 1;
+ hs_enable_flag = false;
+ }
+ write_global_variable(epld->client);
+ LOG_INFO("[%s] Disable HS and recover ps setting \r\n", __func__);
+ }
+#endif
+#if PS_GES
+ if(enable_ges == 1 && mode == 1)
+ {
+ epld->enable_gflag = 0;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = true;
+ LOG_INFO("[%s] Disable GES and recover ps setting \r\n", __func__);
+ }
+ else if (ps_ges_enable_flag == true && mode == 0)
+ {
+ epld->enable_gflag = 1;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = false;
+ LOG_INFO("[%s] enable GES and recover ges setting \r\n", __func__);
+ }
+#endif
+ if(epld->enable_pflag != mode)
+ {
+ epld->enable_pflag = mode;
+ if(mode)
+ {
+ wake_lock(&ps_lock);
+#if PS_DYN_K
+ dynk_min_ps_raw_data = 0xffff;
+ dynk_change_flag = false;
+#if PS_DYN_K_STR
+ dynk_enhance_flag = false;
+#endif
+#endif
+ }
+ else
+ {
+#if PS_DYN_K
+ cancel_delayed_work(&dynk_thd_polling_work);
+#endif
+ wake_unlock(&ps_lock);
+ }
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_show_cal_raw(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ u16 ch1 = 0;
+ u32 ch1_all=0;
+ int count =5;
+ int i;
+ ssize_t len = 0;
+#if !PS_DYN_K
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+#endif
+
+ if(!epl_sensor_obj)
+ {
+ LOG_ERR("epl_sensor_obj is null!!\n");
+ return 0;
+ }
+
+
+
+ for(i=0; i<count; i++)
+ {
+ switch(epl_sensor.mode)
+ {
+ msleep(50);
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS:
+#endif
+#if !PS_DYN_K
+ if(enable_ps == true && polling_flag == true && eint_flag == true && epl_sensor.ps.polling_mode == 0)
+ epl_sensor_read_ps(epld->client);
+#endif
+ ch1 = epl_sensor.ps.data.data;
+ break;
+
+ case EPL_MODE_ALS:
+ if(epl_sensor.als.polling_mode == 0)
+ epl_sensor_read_als(epld->client);
+ ch1 = epl_sensor.als.data.channels[1];
+ break;
+ }
+
+ ch1_all = ch1_all + ch1;
+ if(epl_sensor.wait == EPL_WAIT_SINGLE)
+ epl_sensor_I2C_Write(epld->client,0x11, epl_sensor.power | epl_sensor.reset);
+ }
+
+ ch1 = (u16)(ch1_all/count);
+
+ LOG_INFO("cal_raw = %d \r\n" , ch1);
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d \r\n", ch1);
+
+ return len;
+}
+
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_threshold(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int hthr = 0, lthr = 0;
+ if(!epld)
+ {
+ LOG_ERR("epl_sensor_obj is null!!\n");
+ return 0;
+ }
+
+ switch(epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS:
+#endif
+ sscanf(buf, "%d,%d", &lthr, &hthr);
+ epl_sensor.ps.low_threshold = lthr;
+ epl_sensor.ps.high_threshold = hthr;
+ set_psensor_intr_threshold(epl_sensor.ps.low_threshold, epl_sensor.ps.high_threshold);
+ break;
+
+ case EPL_MODE_ALS:
+ sscanf(buf, "%d,%d", &lthr, &hthr);
+ epl_sensor.als.low_threshold = lthr;
+ epl_sensor.als.high_threshold = hthr;
+ set_lsensor_intr_threshold(epl_sensor.als.low_threshold, epl_sensor.als.high_threshold);
+ break;
+
+ }
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_wait_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int val;
+ sscanf(buf, "%d",&val);
+
+ epl_sensor.wait = (val & 0xf) << 4;
+
+ return count;
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_gain(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int value = 0;
+ LOG_FUN();
+
+ sscanf(buf, "%d", &value);
+
+ value = value & 0x03;
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ epl_sensor.ps.gain = value;
+ epl_sensor_I2C_Write(epld->client, 0x03, epl_sensor.ps.integration_time | epl_sensor.ps.gain);
+ break;
+
+ case EPL_MODE_ALS: //als
+ epl_sensor.als.gain = value;
+ epl_sensor_I2C_Write(epld->client, 0x01, epl_sensor.als.integration_time | epl_sensor.als.gain);
+ break;
+ }
+
+ epl_sensor_update_mode(epld->client);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int value=0;
+
+ LOG_FUN();
+
+ epld->enable_pflag = 0;
+ epld->enable_lflag = 0;
+
+ sscanf(buf, "%d",&value);
+
+ switch (value)
+ {
+ case 0:
+ epl_sensor.mode = EPL_MODE_IDLE;
+ break;
+
+ case 1:
+ epld->enable_lflag = 1;
+ epl_sensor.mode = EPL_MODE_ALS;
+ break;
+
+ case 2:
+ epld->enable_pflag = 1;
+ epl_sensor.mode = EPL_MODE_PS;
+ break;
+
+ case 3:
+ epld->enable_lflag = 1;
+ epld->enable_pflag = 1;
+ epl_sensor.mode = EPL_MODE_ALS_PS;
+ break;
+ }
+
+ epl_sensor_update_mode(epld->client);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_ir_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d", &value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ switch(value)
+ {
+ case 0:
+ epl_sensor.ps.ir_mode = EPL_IR_MODE_CURRENT;
+ break;
+
+ case 1:
+ epl_sensor.ps.ir_mode = EPL_IR_MODE_VOLTAGE;
+ break;
+ }
+
+ epl_sensor_I2C_Write(epld->client,0x05, epl_sensor.ps.ir_on_control | epl_sensor.ps.ir_mode | epl_sensor.ps.ir_drive);
+ break;
+ }
+
+ epl_sensor_I2C_Write(epld->client,0x00,epl_sensor.wait | epl_sensor.mode);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_ir_contrl(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+ uint8_t data;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d",&value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ switch(value)
+ {
+ case 0:
+ epl_sensor.ps.ir_on_control = EPL_IR_ON_CTRL_OFF;
+ break;
+
+ case 1:
+ epl_sensor.ps.ir_on_control = EPL_IR_ON_CTRL_ON;
+ break;
+ }
+
+ data = epl_sensor.ps.ir_on_control | epl_sensor.ps.ir_mode | epl_sensor.ps.ir_drive;
+ LOG_INFO("[%s]: 0x05 = 0x%x\n", __FUNCTION__, data);
+
+ epl_sensor_I2C_Write(epld->client,0x05, epl_sensor.ps.ir_on_control | epl_sensor.ps.ir_mode | epl_sensor.ps.ir_drive);
+ break;
+ }
+
+ epl_sensor_I2C_Write(epld->client,0x00,epl_sensor.wait | epl_sensor.mode);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_ir_drive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d", &value);
+
+ switch(epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS:
+#endif
+ epl_sensor.ps.ir_drive = (value & 0x03);
+ epl_sensor_I2C_Write(epld->client,0x05, epl_sensor.ps.ir_on_control | epl_sensor.ps.ir_mode | epl_sensor.ps.ir_drive);
+ break;
+ }
+
+ epl_sensor_I2C_Write(epld->client,0x00,epl_sensor.wait | epl_sensor.mode);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_interrupt_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d",&value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ if(!epl_sensor.ps.polling_mode)
+ {
+ epl_sensor.ps.interrupt_type = value & 0x03;
+ epl_sensor_I2C_Write(epld->client,0x06, epl_sensor.interrupt_control | epl_sensor.ps.persist |epl_sensor.ps.interrupt_type);
+ LOG_INFO("[%s]: 0x06 = 0x%x\n", __FUNCTION__, epl_sensor.interrupt_control | epl_sensor.ps.persist |epl_sensor.ps.interrupt_type);
+ }
+ break;
+
+ case EPL_MODE_ALS: //als
+ if(!epl_sensor.als.polling_mode)
+ {
+ epl_sensor.als.interrupt_type = value & 0x03;
+ epl_sensor_I2C_Write(epld->client,0x07, epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type);
+ LOG_INFO("[%s]: 0x07 = 0x%x\n", __FUNCTION__, epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type);
+ }
+ break;
+ }
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static ssize_t epl_sensor_store_ps_polling_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int polling_mode = 0;
+
+
+ sscanf(buf, "%d",&polling_mode);
+ epl_sensor.ps.polling_mode = polling_mode;
+#if PS_GES
+ epl_sensor.ges.polling_mode = polling_mode;
+#endif
+
+ epl_sensor_update_mode(epld->client);
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_als_polling_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int polling_mode = 0;
+
+ sscanf(buf, "%d",&polling_mode);
+ epl_sensor.als.polling_mode = polling_mode;
+
+ epl_sensor_update_mode(epld->client);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_integration(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d",&value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ epl_sensor.ps.integration_time = (value & 0xf) << 2;
+ epl_sensor_I2C_Write(epld->client,0x03, epl_sensor.ps.integration_time | epl_sensor.ps.gain);
+ epl_sensor_I2C_Read(epld->client, 0x03, 1);
+ LOG_INFO("[%s]: 0x03 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.ps.integration_time | epl_sensor.ps.gain, gRawData.raw_bytes[0]);
+ break;
+
+ case EPL_MODE_ALS: //als
+ epl_sensor.als.integration_time = (value & 0xf) << 2;
+ epl_sensor_I2C_Write(epld->client,0x01, epl_sensor.als.integration_time | epl_sensor.als.gain);
+ epl_sensor_I2C_Read(epld->client, 0x01, 1);
+ LOG_INFO("[%s]: 0x01 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.als.integration_time | epl_sensor.als.gain, gRawData.raw_bytes[0]);
+ break;
+ }
+
+ epl_sensor_update_mode(epld->client);
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_adc(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d",&value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ epl_sensor.ps.adc = (value & 0x3) << 3;
+ epl_sensor_I2C_Write(epld->client,0x04, epl_sensor.ps.adc | epl_sensor.ps.cycle);
+ epl_sensor_I2C_Read(epld->client, 0x04, 1);
+ LOG_INFO("[%s]:0x04 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.ps.adc | epl_sensor.ps.cycle, gRawData.raw_bytes[0]);
+ break;
+
+ case EPL_MODE_ALS: //als
+ epl_sensor.als.adc = (value & 0x3) << 3;
+ epl_sensor_I2C_Write(epld->client,0x02, epl_sensor.als.adc | epl_sensor.als.cycle);
+ epl_sensor_I2C_Read(epld->client, 0x02, 1);
+ LOG_INFO("[%s]:0x02 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.als.adc | epl_sensor.als.cycle, gRawData.raw_bytes[0]);
+ break;
+ }
+
+ epl_sensor_update_mode(epld->client);
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_cycle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d",&value);
+
+ switch (epl_sensor.mode)
+ {
+#if PS_DYN_K_STR
+ case EPL_MODE_ALS_PS:
+#else
+ case EPL_MODE_PS: //ps
+#endif
+ epl_sensor.ps.cycle = (value & 0x7);
+ epl_sensor_I2C_Write(epld->client,0x04, epl_sensor.ps.adc | epl_sensor.ps.cycle);
+ LOG_INFO("[%s]:0x04 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.ps.adc | epl_sensor.ps.cycle, gRawData.raw_bytes[0]);
+ break;
+
+ case EPL_MODE_ALS: //als
+ epl_sensor.als.cycle = (value & 0x7);
+ epl_sensor_I2C_Write(epld->client,0x02, epl_sensor.als.adc | epl_sensor.als.cycle);
+ LOG_INFO("[%s]:0x02 = 0x%x (0x%x)\n", __FUNCTION__, epl_sensor.als.adc | epl_sensor.als.cycle, gRawData.raw_bytes[0]);
+ break;
+ }
+
+ epl_sensor_update_mode(epld->client);
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_als_report_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value=0;
+
+ LOG_FUN();
+
+ sscanf(buf, "%d", &value);
+ epl_sensor.als.report_type = value & 0xf;
+
+ return count;
+}
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_store_ps_w_calfile(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int ps_hthr=0, ps_lthr=0, ps_cancelation=0;
+ int ps_cal_len = 0;
+ char ps_calibration[20];
+ LOG_FUN();
+
+ if(!epl_sensor_obj)
+ {
+ LOG_ERR("epl_obj is null!!\n");
+ return 0;
+ }
+ sscanf(buf, "%d,%d,%d",&ps_cancelation, &ps_hthr, &ps_lthr);
+
+ ps_cal_len = sprintf(ps_calibration, "%d,%d,%d", ps_cancelation, ps_hthr, ps_lthr);
+
+ write_factory_calibration(epld, ps_calibration, ps_cal_len);
+ return count;
+}
+/*----------------------------------------------------------------------------*/
+
+static ssize_t epl_sensor_store_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int reg;
+ int data;
+ LOG_FUN();
+
+ sscanf(buf, "%x,%x",&reg, &data);
+
+ LOG_INFO("[%s]: reg=0x%x, data=0x%x", __func__, reg, data);
+ epl_sensor_I2C_Write(epld->client, reg, data);
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_unlock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int mode;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&mode);
+
+ LOG_INFO("mode = %d \r\n", mode);
+ switch (mode)
+ {
+ case 0: //ps
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+ break;
+
+ case 1: //als
+ //ALS unlock and run
+ epl_sensor.als.compare_reset = EPL_CMP_RUN;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ break;
+
+ case 2: //als unlock and reset
+ epl_sensor.als.compare_reset = EPL_CMP_RESET;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ break;
+
+ case 3: //ps+als
+ //PS unlock and run
+ epl_sensor.ps.compare_reset = EPL_CMP_RUN;
+ epl_sensor.ps.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x1b, epl_sensor.ps.compare_reset |epl_sensor.ps.lock);
+
+ //ALS unlock and run
+ epl_sensor.als.compare_reset = EPL_CMP_RUN;
+ epl_sensor.als.lock = EPL_UN_LOCK;
+ epl_sensor_I2C_Write(epld->client,0x12, epl_sensor.als.compare_reset | epl_sensor.als.lock);
+ break;
+ }
+ /*double check PS or ALS lock*/
+
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_als_ch_sel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int ch_sel;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&ch_sel);
+
+ LOG_INFO("channel selection = %d \r\n", ch_sel);
+ switch (ch_sel)
+ {
+ case 0: //ch0
+ epl_sensor.als.interrupt_channel_select = EPL_ALS_INT_CHSEL_0;
+ break;
+
+ case 1: //ch1
+ epl_sensor.als.interrupt_channel_select = EPL_ALS_INT_CHSEL_1;
+ break;
+ }
+ epl_sensor_I2C_Write(epld->client,0x07, epl_sensor.als.interrupt_channel_select | epl_sensor.als.persist | epl_sensor.als.interrupt_type);
+
+ epl_sensor_update_mode(epld->client);
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_ps_cancelation(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int cancelation;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&cancelation);
+
+ epl_sensor.ps.cancelation = cancelation;
+
+ LOG_INFO("epl_sensor.ps.cancelation = %d \r\n", epl_sensor.ps.cancelation);
+
+ epl_sensor_I2C_Write(epld->client,0x22, (u8)(epl_sensor.ps.cancelation& 0xff));
+ epl_sensor_I2C_Write(epld->client,0x23, (u8)((epl_sensor.ps.cancelation & 0xff00) >> 8));
+
+ return count;
+}
+
+static ssize_t epl_sensor_show_ps_polling(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u16 *tmp = (u16*)buf;
+ tmp[0]= epl_sensor.ps.polling_mode;
+ return 2;
+}
+
+static ssize_t epl_sensor_show_als_polling(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u16 *tmp = (u16*)buf;
+ tmp[0]= epl_sensor.als.polling_mode;
+ return 2;
+}
+
+static ssize_t epl_sensor_show_ps_run_cali(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ ssize_t len = 0;
+ int ret;
+
+ LOG_FUN();
+
+ ret = epl_run_ps_calibration(epld);
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "ret = %d\r\n", ret);
+
+ return len;
+}
+
+static ssize_t epl_sensor_show_pdata(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ ssize_t len = 0;
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+ LOG_FUN();
+
+ if(enable_ps == true && polling_flag == true && eint_flag == true && epl_sensor.ps.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_ps(epld->client);
+ mutex_unlock(&sensor_mutex);
+ }
+ LOG_INFO("[%s]: epl_sensor.ps.data.data = %d \r\n", __func__, epl_sensor.ps.data.data);
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d", epl_sensor.ps.data.data);
+ return len;
+
+}
+
+static ssize_t epl_sensor_show_als_data(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ ssize_t len = 0;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+ LOG_FUN();
+
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ LOG_INFO("[%s]: dynamic_intt_lux = %d \r\n", __func__, dynamic_intt_lux);
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d", dynamic_intt_lux);
+ }
+ else
+#endif
+ {
+ if(enable_als == true && polling_flag == true && eint_flag == true && epl_sensor.als.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_als(epld->client);
+ mutex_unlock(&sensor_mutex);
+ }
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d", epl_sensor.als.data.channels[1]);
+ }
+
+ return len;
+}
+
+#if ALS_DYN_INTT
+static ssize_t epl_sensor_store_c_gain(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int c_h,c_l;
+ LOG_FUN();
+
+ if(epl_sensor.als.lsrc_type == CMC_BIT_LSRC_NON)
+ {
+ sscanf(buf, "%d",&c_h);
+ c_gain = c_h;
+ LOG_INFO("c_gain = %d \r\n", c_gain);
+ }
+ else
+ {
+ sscanf(buf, "%d,%d",&c_l, &c_h);
+ epld->c_gain_h = c_h;
+ epld->c_gain_l = c_l;
+ }
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_lsrc_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int type;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&type);
+
+ epl_sensor.als.lsrc_type = type;
+
+ LOG_INFO("epl_sensor.als.lsrc_type = %d \r\n", epl_sensor.als.lsrc_type);
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_lsrc_thd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int lsrc_thrl, lsrc_thrh;
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ sscanf(buf, "%d,%d",&lsrc_thrl, &lsrc_thrh);
+
+ epld->lsource_thd_low = lsrc_thrl;
+ epld->lsource_thd_high = lsrc_thrh;
+
+ LOG_INFO("lsource_thd=(%d,%d) \r\n", epld->lsource_thd_low, epld->lsource_thd_high);
+
+ return count;
+}
+
+#endif
+
+#if PS_DYN_K
+static ssize_t epl_sensor_store_dyn_offset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int dyn_h,dyn_l;
+ LOG_FUN();
+
+ sscanf(buf, "%d,%d",&dyn_l, &dyn_h);
+
+ dynk_low_offset = dyn_l;
+ dynk_high_offset = dyn_h;
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_dyn_thd_offset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int thd_offset;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&thd_offset);
+ dynk_thd_offset = thd_offset;
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_dyn_change_thd_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int thd_max;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&thd_max);
+ dynk_change_thd_max = thd_max;
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_dyn_max_ir_data(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int max_ir_data;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&max_ir_data);
+ dynk_max_ir_data = max_ir_data;
+
+ return count;
+}
+
+#if PS_DYN_K_STR
+static ssize_t epl_sensor_store_dyn_enhance_max_ch0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ //struct epl_sensor_priv *epld = epl_sensor_obj;
+ int max_ch0;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&max_ch0);
+ dynk_enhance_max_ch0 = max_ch0;
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_dyn_enhance_gain_intt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ //struct epl_sensor_priv *epld = epl_sensor_obj;
+ int gain, intt;
+ LOG_FUN();
+
+ sscanf(buf, "%d,%d",&gain, &intt);
+
+ dynk_enhance_integration_time = intt;
+ dynk_enhance_gain = gain;
+
+ return count;
+}
+#endif
+
+#endif
+
+#if HS_ENABLE
+static ssize_t epl_sensor_show_renvo(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+
+ LOG_FUN();
+ LOG_INFO("gRawData.renvo=0x%x \r\n", epl_sensor.revno);
+
+ len += snprintf(buf+len, PAGE_SIZE-len, "%x", epl_sensor.revno);
+
+ return len;
+}
+
+static ssize_t epl_sensor_store_hs_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint16_t mode=0;
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ bool enable_ps = obj->enable_pflag==1 && obj->ps_suspend==0;
+ bool enable_als = obj->enable_lflag==1 && obj->als_suspend==0;
+ LOG_FUN();
+
+ sscanf(buf, "%hu",&mode);
+
+ if(enable_ps == 0)
+ {
+ if(mode > 0)
+ {
+ if(enable_als == 1)
+ {
+ obj->enable_lflag = 0;
+ hs_enable_flag = true;
+ }
+ epl_sensor.hs.integration_time = epl_sensor.hs.integration_time_max;
+ epl_sensor.hs.raws_count=0;
+ obj->enable_hflag = 1;
+
+ if(mode == 2)
+ {
+ epl_sensor.hs.dynamic_intt = false;
+ }
+ else
+ {
+ epl_sensor.hs.dynamic_intt = true;
+ }
+ }
+ else
+ {
+ obj->enable_hflag = 0;
+ if(hs_enable_flag == true)
+ {
+ obj->enable_lflag = 1;
+ hs_enable_flag = false;
+ }
+
+ }
+ write_global_variable(obj->client);
+ epl_sensor_update_mode(obj->client);
+ }
+
+ return count;
+}
+
+static ssize_t epl_sensor_store_hs_int_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ int value;
+ u8 intt_buf;
+
+ sscanf(buf, "%d",&value);
+
+ mutex_lock(&hs_sensor_mutex);
+ epl_sensor.hs.integration_time = value<<2;
+ intt_buf = epl_sensor.hs.integration_time | epl_sensor.hs.gain;
+ epl_sensor_I2C_Write(obj->client, 0x03, intt_buf);
+ mutex_unlock(&hs_sensor_mutex);
+
+ return count;
+}
+
+/*----------------------------------------------------------------------------*/
+static ssize_t epl_sensor_show_hs_raws(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u16 *tmp = (u16*)buf;
+ int byte_count=2+epl_sensor.hs.raws_count*2;
+ int i=0;
+ LOG_FUN();
+ mutex_lock(&hs_sensor_mutex);
+ tmp[0]= epl_sensor.hs.raws_count;
+
+ for(i=0; i<epl_sensor.hs.raws_count; i++){
+ tmp[i+1] = epl_sensor.hs.raws[i];
+ }
+
+ epl_sensor.hs.raws_count=0;
+ mutex_unlock(&hs_sensor_mutex);
+
+ return byte_count;
+}
+#endif
+
+#if PS_GES
+static ssize_t epl_sensor_store_ges_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ges_enable=0;
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ struct i2c_client *client = obj->client;
+ bool enable_ps = obj->enable_pflag==1 && obj->ps_suspend==0;
+ LOG_FUN();
+
+ sscanf(buf, "%d",&ges_enable);
+ LOG_INFO("[%s]: enable_ps=%d, ges_enable=%d \r\n", __func__, enable_ps, ges_enable);
+
+ if(enable_ps == 0)
+ {
+ if(ges_enable == 1)
+ {
+ obj->enable_gflag = 1;
+ }
+ else
+ {
+ obj->enable_gflag = 0;
+ }
+ }
+
+ write_global_variable(obj->client);
+ epl_sensor_update_mode(client);
+ return count;
+}
+
+static ssize_t epl_sensor_store_ges_polling_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ges_mode=0;
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ struct i2c_client *client = obj->client;
+
+ LOG_FUN();
+ sscanf(buf, "%d",&ges_mode);
+ LOG_INFO("[%s]: ges_mode=%d \r\n", __func__, ges_mode);
+
+ epl_sensor.ges.polling_mode = ges_mode;
+ epl_sensor.ps.polling_mode = ges_mode;
+
+ epl_sensor_update_mode(client);
+ return count;
+}
+
+static ssize_t epl_sensor_store_ges_thd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ges_l=0, ges_h=0;
+ struct epl_sensor_priv *obj = epl_sensor_obj;
+ struct i2c_client *client = obj->client;
+
+ LOG_FUN();
+ sscanf(buf, "%d,%d",&ges_l, &ges_h);
+ epl_sensor.ges.low_threshold = ges_l;
+ epl_sensor.ges.high_threshold = ges_h;
+ LOG_INFO("[%s]: ges_thd=%d,%d \r\n", __func__, epl_sensor.ges.low_threshold, epl_sensor.ges.high_threshold);
+
+ write_global_variable(obj->client);
+ epl_sensor_update_mode(client);
+ return count;
+}
+
+#endif
+/*----------------------------------------------------------------------------*/
+
+static DEVICE_ATTR(elan_status, S_IROTH | S_IWOTH, epl_sensor_show_status, NULL );
+static DEVICE_ATTR(elan_reg, S_IROTH | S_IWOTH, epl_sensor_show_reg, NULL );
+static DEVICE_ATTR(mode, S_IROTH | S_IWOTH, NULL, epl_sensor_store_mode );
+static DEVICE_ATTR(wait_time, S_IROTH | S_IWOTH, NULL, epl_sensor_store_wait_time );
+static DEVICE_ATTR(set_threshold, S_IROTH | S_IWOTH, NULL, epl_sensor_store_threshold );
+static DEVICE_ATTR(cal_raw, S_IROTH | S_IWOTH, epl_sensor_show_cal_raw, NULL );
+static DEVICE_ATTR(als_enable, S_IROTH | S_IWOTH, NULL, epl_sensor_store_als_enable );
+static DEVICE_ATTR(als_report_type, S_IROTH | S_IWOTH, NULL, epl_sensor_store_als_report_type );
+static DEVICE_ATTR(ps_enable, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ps_enable );
+static DEVICE_ATTR(ps_polling_mode, S_IROTH | S_IWOTH, epl_sensor_show_ps_polling, epl_sensor_store_ps_polling_mode );
+static DEVICE_ATTR(als_polling_mode, S_IROTH | S_IWOTH, epl_sensor_show_als_polling, epl_sensor_store_als_polling_mode );
+static DEVICE_ATTR(gain, S_IROTH | S_IWOTH, NULL, epl_sensor_store_gain );
+static DEVICE_ATTR(ir_mode, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ir_mode );
+static DEVICE_ATTR(ir_drive, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ir_drive );
+static DEVICE_ATTR(ir_on, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ir_contrl );
+static DEVICE_ATTR(interrupt_type, S_IROTH | S_IWOTH, NULL, epl_sensor_store_interrupt_type );
+static DEVICE_ATTR(integration, S_IROTH | S_IWOTH, NULL, epl_sensor_store_integration );
+static DEVICE_ATTR(adc, S_IROTH | S_IWOTH, NULL, epl_sensor_store_adc );
+static DEVICE_ATTR(cycle, S_IROTH | S_IWOTH, NULL, epl_sensor_store_cycle );
+static DEVICE_ATTR(ps_w_calfile, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ps_w_calfile );
+static DEVICE_ATTR(i2c_w, S_IROTH | S_IWOTH, NULL, epl_sensor_store_reg_write );
+static DEVICE_ATTR(unlock, S_IROTH | S_IWOTH, NULL, epl_sensor_store_unlock );
+static DEVICE_ATTR(als_ch, S_IROTH | S_IWOTH, NULL, epl_sensor_store_als_ch_sel );
+static DEVICE_ATTR(ps_cancel, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ps_cancelation );
+static DEVICE_ATTR(run_ps_cali, S_IROTH | S_IWOTH, epl_sensor_show_ps_run_cali, NULL );
+static DEVICE_ATTR(pdata, S_IROTH | S_IWOTH, epl_sensor_show_pdata, NULL );
+static DEVICE_ATTR(als_data, S_IROTH | S_IWOTH, epl_sensor_show_als_data, NULL );
+#if ALS_DYN_INTT
+static DEVICE_ATTR(als_dyn_c_gain, S_IROTH | S_IWOTH, NULL, epl_sensor_store_c_gain);
+static DEVICE_ATTR(als_dyn_lsrc_type, S_IROTH | S_IWOTH, NULL, epl_sensor_store_lsrc_type);
+static DEVICE_ATTR(als_dyn_lsrc_thd, S_IROTH | S_IWOTH, NULL, epl_sensor_store_lsrc_thd);
+#endif
+#if PS_DYN_K
+static DEVICE_ATTR(dyn_offset, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_offset);
+static DEVICE_ATTR(dyn_thd_offset, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_thd_offset);
+static DEVICE_ATTR(dyn_change_max, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_change_thd_max);
+static DEVICE_ATTR(dyn_max_ir_data, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_max_ir_data );
+#if PS_DYN_K_STR
+static DEVICE_ATTR(dyn_enh_max_ch0, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_enhance_max_ch0 );
+static DEVICE_ATTR(dyn_enh_gain_intt, S_IROTH | S_IWOTH, NULL, epl_sensor_store_dyn_enhance_gain_intt );
+#endif
+#endif
+#if HS_ENABLE
+static DEVICE_ATTR(elan_renvo, S_IROTH | S_IWOTH, epl_sensor_show_renvo, NULL );
+static DEVICE_ATTR(hs_enable, S_IROTH | S_IWOTH, NULL, epl_sensor_store_hs_enable );
+static DEVICE_ATTR(hs_int_time, S_IROTH | S_IWOTH, NULL, epl_sensor_store_hs_int_time );
+static DEVICE_ATTR(hs_raws, S_IROTH | S_IWOTH, epl_sensor_show_hs_raws, NULL );
+#endif
+#if PS_GES
+static DEVICE_ATTR(ges_enable, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ges_enable );
+static DEVICE_ATTR(ges_polling_mode, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ges_polling_mode );
+static DEVICE_ATTR(ges_thd, S_IROTH | S_IWOTH, NULL, epl_sensor_store_ges_thd );
+#endif
+/*----------------------------------------------------------------------------*/
+static struct attribute *epl_sensor_attr_list[] =
+{
+ &dev_attr_elan_status.attr,
+ &dev_attr_elan_reg.attr,
+ &dev_attr_als_enable.attr,
+ &dev_attr_ps_enable.attr,
+ &dev_attr_cal_raw.attr,
+ &dev_attr_set_threshold.attr,
+ &dev_attr_wait_time.attr,
+ &dev_attr_gain.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_ir_mode.attr,
+ &dev_attr_ir_drive.attr,
+ &dev_attr_ir_on.attr,
+ &dev_attr_interrupt_type.attr,
+ &dev_attr_integration.attr,
+ &dev_attr_adc.attr,
+ &dev_attr_cycle.attr,
+ &dev_attr_als_report_type.attr,
+ &dev_attr_ps_polling_mode.attr,
+ &dev_attr_als_polling_mode.attr,
+ &dev_attr_ps_w_calfile.attr,
+ &dev_attr_i2c_w.attr,
+ &dev_attr_unlock.attr,
+ &dev_attr_als_ch.attr,
+ &dev_attr_ps_cancel.attr,
+ &dev_attr_run_ps_cali.attr,
+ &dev_attr_pdata.attr,
+ &dev_attr_als_data.attr,
+#if ALS_DYN_INTT
+ &dev_attr_als_dyn_c_gain.attr,
+ &dev_attr_als_dyn_lsrc_type.attr,
+ &dev_attr_als_dyn_lsrc_thd.attr,
+#endif
+#if PS_DYN_K
+ &dev_attr_dyn_offset.attr,
+ &dev_attr_dyn_thd_offset.attr,
+ &dev_attr_dyn_change_max.attr,
+ &dev_attr_dyn_max_ir_data.attr,
+#if PS_DYN_K_STR
+ &dev_attr_dyn_enh_max_ch0.attr,
+ &dev_attr_dyn_enh_gain_intt.attr,
+#endif
+#endif
+#if HS_ENABLE
+ &dev_attr_elan_renvo.attr,
+ &dev_attr_hs_enable.attr,
+ &dev_attr_hs_int_time.attr,
+ &dev_attr_hs_raws.attr,
+#endif
+#if PS_GES
+ &dev_attr_ges_enable.attr,
+ &dev_attr_ges_polling_mode.attr,
+ &dev_attr_ges_thd.attr,
+#endif
+};
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct attribute_group epl_sensor_attr_group =
+{
+ .attrs = epl_sensor_attr_list,
+};
+/*----------------------------------------------------------------------------*/
+#if !(SPREAD || MARVELL)/*SPREAD MARVELL start.....*/
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_als_open(struct inode *inode, struct file *file)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ if (epld->als_opened)
+ {
+ return -EBUSY;
+ }
+ epld->als_opened = 1;
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_als_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ int buf[1];
+ if(epld->read_flag ==1)
+ {
+ buf[0] = epl_sensor.als.data.channels[1];
+ if(copy_to_user(buffer, &buf , sizeof(buf)))
+ return 0;
+ epld->read_flag = 0;
+ return 12;
+ }
+ else
+ {
+ return 0;
+ }
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_als_release(struct inode *inode, struct file *file)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ epld->als_opened = 0;
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static long epl_sensor_als_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int flag;
+ unsigned long buf[1];
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ bool enable_als = epld->enable_lflag==1 && epld->als_suspend==0;
+ void __user *argp = (void __user *)arg;
+
+ LOG_INFO("als io ctrl cmd %d\n", _IOC_NR(cmd));
+
+ switch(cmd)
+ {
+ case ELAN_EPL8800_IOCTL_GET_LFLAG:
+
+ LOG_INFO("elan ambient-light IOCTL Sensor get lflag \n");
+ flag = epld->enable_lflag;
+ if (copy_to_user(argp, &flag, sizeof(flag)))
+ return -EFAULT;
+
+ LOG_INFO("elan ambient-light Sensor get lflag %d\n",flag);
+ break;
+
+ case ELAN_EPL8800_IOCTL_ENABLE_LFLAG:
+#if LEADCORE
+ case LIGHT_SET_ENALBE:
+#endif
+ LOG_INFO("elan ambient-light IOCTL Sensor set lflag \n");
+ if (copy_from_user(&flag, argp, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+
+ if(epld->enable_lflag != flag)
+ {
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ dynamic_intt_idx = dynamic_intt_init_idx;
+ epl_sensor.als.integration_time = als_dynamic_intt_intt[dynamic_intt_idx];
+ epl_sensor.als.gain = als_dynamic_intt_gain[dynamic_intt_idx];
+ dynamic_intt_high_thr = als_dynamic_intt_high_thr[dynamic_intt_idx];
+ dynamic_intt_low_thr = als_dynamic_intt_low_thr[dynamic_intt_idx];
+ }
+#endif
+ epld->enable_lflag = flag;
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ LOG_INFO("elan ambient-light Sensor set lflag %d\n",flag);
+ break;
+
+ case ELAN_EPL8800_IOCTL_GETDATA:
+ if(enable_als == 0)
+ {
+ epld->enable_lflag = 1;
+ epl_sensor_update_mode(epld->client);
+ msleep(30);
+ }
+
+ if(enable_als == true && polling_flag == true && eint_flag == true && epl_sensor.als.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_als(epld->client);
+ mutex_unlock(&sensor_mutex);
+ }
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ buf[0] = dynamic_intt_lux;
+ LOG_INFO("[%s]: als dynamic_intt_lux = %d \r\n", __func__, dynamic_intt_lux);
+ }
+ else
+#else
+ {
+ buf[0] = epl_sensor.als.data.channels[1];
+ LOG_INFO("[%s]: epl_sensor.als.data.channels[1] = %d \r\n", __func__, epl_sensor.als.data.channels[1]);
+ }
+#endif
+
+ if(copy_to_user(argp, &buf , sizeof(buf)))
+ return -EFAULT;
+
+ break;
+#if LEADCORE
+ case LIGHT_SET_DELAY:
+
+ if (arg > LIGHT_MAX_DELAY)
+ arg = LIGHT_MAX_DELAY;
+ else if (arg < LIGHT_MIN_DELAY)
+ arg = LIGHT_MIN_DELAY;
+ LOG_INFO("LIGHT_SET_DELAY--%d\r\n",(int)arg);
+ polling_time = arg;
+ break;
+#endif
+ default:
+ LOG_ERR("invalid cmd %d\n", _IOC_NR(cmd));
+ return -EINVAL;
+ }
+
+ return 0;
+
+
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct file_operations epl_sensor_als_fops =
+{
+ .owner = THIS_MODULE,
+ .open = epl_sensor_als_open,
+ .read = epl_sensor_als_read,
+ .release = epl_sensor_als_release,
+ .unlocked_ioctl = epl_sensor_als_ioctl
+};
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct miscdevice epl_sensor_als_device =
+{
+ .minor = MISC_DYNAMIC_MINOR,
+#if LEADCORE
+ .name = "light",
+#else
+ .name = "elan_als",
+#endif
+ .fops = &epl_sensor_als_fops
+};
+/*----------------------------------------------------------------------------*/
+#endif /*SPREAD MARVELL end.........*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_ps_open(struct inode *inode, struct file *file)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ if (epld->ps_opened)
+ return -EBUSY;
+
+ epld->ps_opened = 1;
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_ps_release(struct inode *inode, struct file *file)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+
+ LOG_FUN();
+
+ epld->ps_opened = 0;
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+
+static int epl259x_read_chip_info(struct i2c_client *client, char *buf)
+{
+ if(NULL == buf) {
+ return -1;
+ }
+ if(NULL == client) {
+ *buf = 0;
+ return -2;
+ }
+
+ sprintf(buf, "EPL2182");
+ printk("[EPL259x] epl259x_read_chip_info %s\n",buf);
+ return 0;
+}
+
+static long epl_sensor_ps_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int value;
+ int flag,err =0;
+ char strbuf[100];
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ bool enable_ps = epld->enable_pflag==1 && epld->ps_suspend==0;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+#endif
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+ void __user *argp = (void __user *)arg;
+
+ LOG_INFO("ps io ctrl cmd %d\n", _IOC_NR(cmd));
+
+ //ioctl message handle must define by android sensor library (case by case)
+ switch(cmd)
+ {
+ case ELAN_EPL8800_IOCTL_GET_PFLAG:
+#if MARVELL
+ case LTR_IOCTL_GET_PFLAG:
+#endif
+ LOG_INFO("elan Proximity Sensor IOCTL get pflag \n");
+ flag = epld->enable_pflag;
+ if (copy_to_user(argp, &flag, sizeof(flag)))
+ return -EFAULT;
+
+ LOG_INFO("elan Proximity Sensor get pflag %d\n",flag);
+ break;
+
+ case ELAN_EPL8800_IOCTL_ENABLE_PFLAG:
+#if LEADCORE
+ case PROXIMITY_SET_ENALBE:
+#elif MARVELL
+ case LTR_IOCTL_SET_PFLAG:
+#endif
+ LOG_INFO("elan Proximity IOCTL Sensor set pflag \n");
+ if (copy_from_user(&flag, argp, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+#if HS_ENABLE
+ if(enable_hs == 1 && flag == 1)
+ {
+ epld->enable_hflag = 0;
+ if(hs_enable_flag == true)
+ {
+ epld->enable_lflag = 1;
+ hs_enable_flag = false;
+ }
+ write_global_variable(epld->client);
+ LOG_INFO("[%s] Disable HS and recover ps setting \r\n", __func__);
+ }
+#endif
+#if PS_GES
+ if(enable_ges == 1 && flag == 1)
+ {
+ epld->enable_gflag = 0;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = true;
+ LOG_INFO("[%s] Disable GES and recover ps setting \r\n", __func__);
+ }
+ else if (ps_ges_enable_flag == true && flag == 0)
+ {
+ epld->enable_gflag = 1;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = false;
+ LOG_INFO("[%s] enable GES and recover ges setting \r\n", __func__);
+ }
+#endif
+ if(epld->enable_pflag != flag)
+ {
+ epld->enable_pflag = flag;
+ if(flag)
+ {
+ wake_lock(&ps_lock);
+#if PS_DYN_K
+ dynk_min_ps_raw_data = 0xffff;
+ dynk_change_flag = false;
+#if PS_DYN_K_STR
+ dynk_enhance_flag = false;
+#endif
+#endif
+ }else{
+#if PS_DYN_K
+ cancel_delayed_work(&dynk_thd_polling_work);
+#endif
+ wake_unlock(&ps_lock);
+ }
+ epl_sensor_update_mode(epld->client);
+ }
+
+ LOG_INFO("elan Proximity Sensor set pflag %d\n",flag);
+ break;
+
+ case ELAN_EPL8800_IOCTL_GETDATA:
+ if(enable_ps == 0)
+ {
+ epld->enable_pflag = 1;
+ epl_sensor_update_mode(epld->client);
+ msleep(30);
+ }
+
+ if(enable_ps == true && polling_flag == true && eint_flag == true && epl_sensor.ps.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_ps(epld->client);
+ mutex_unlock(&sensor_mutex);
+ }
+
+ LOG_INFO("[%s]: epl_sensor.ps.data.data = %d \r\n", __func__, epl_sensor.ps.data.data);
+
+ value = epl_sensor.ps.data.data;
+ if(copy_to_user(argp, &value , sizeof(value)))
+ return -EFAULT;
+
+ LOG_INFO("elan proximity Sensor get data (%d) \n",value);
+ break;
+#if LEADCORE
+ case PROXIMITY_SET_DELAY:
+ if (arg > PROXIMITY_MAX_DELAY)
+ arg = PROXIMITY_MAX_DELAY;
+ else if (arg < PROXIMITY_MIN_DELAY)
+ arg = PROXIMITY_MIN_DELAY;
+ LOG_INFO("PROXIMITY_SET_DELAY--%d\r\n",(int)arg);
+ polling_time = arg;
+ break;
+#endif
+
+#if SPREAD || MARVELL /*SPREAD MARVELL start.....*/
+ case ELAN_EPL8800_IOCTL_GET_LFLAG:
+#if MARVELL
+ case LTR_IOCTL_GET_LFLAG:
+#endif
+ LOG_INFO("elan ambient-light IOCTL Sensor get lflag \n");
+ flag = epld->enable_lflag;
+ if (copy_to_user(argp, &flag, sizeof(flag)))
+ return -EFAULT;
+
+ LOG_INFO("elan ambient-light Sensor get lflag %d\n",flag);
+ break;
+
+ case ELAN_EPL8800_IOCTL_GET_CHIPINFO:
+ err = epl259x_read_chip_info(this_client, strbuf);
+ if(err < 0)
+ return -EFAULT;
+ if(copy_to_user(argp, strbuf, strlen(strbuf)+1))
+ return -EFAULT;
+ break;
+
+ case ELAN_EPL8800_IOCTL_ENABLE_LFLAG:
+#if MARVELL
+ case LTR_IOCTL_SET_LFLAG:
+#endif
+ LOG_INFO("elan ambient-light IOCTL Sensor set lflag \n");
+ if (copy_from_user(&flag, argp, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+
+ if(epld->enable_lflag != flag)
+ {
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ dynamic_intt_idx = dynamic_intt_init_idx;
+ epl_sensor.als.integration_time = als_dynamic_intt_intt[dynamic_intt_idx];
+ epl_sensor.als.gain = als_dynamic_intt_gain[dynamic_intt_idx];
+ dynamic_intt_high_thr = als_dynamic_intt_high_thr[dynamic_intt_idx];
+ dynamic_intt_low_thr = als_dynamic_intt_low_thr[dynamic_intt_idx];
+ }
+#endif
+ epld->enable_lflag = flag;
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ LOG_INFO("elan ambient-light Sensor set lflag %d\n",flag);
+ break;
+#if 0
+ case ELAN_EPL8800_IOCTL_GETDATA:
+ if(enable_als == 0)
+ {
+ epld->enable_lflag = 1;
+ epl_sensor_update_mode(epld->client);
+ msleep(30);
+ }
+
+ if(enable_als == true && polling_flag == true && eint_flag == true && epl_sensor.als.polling_mode == 0)
+ {
+ mutex_lock(&sensor_mutex);
+ epl_sensor_read_als(epld->client);
+ mutex_unlock(&sensor_mutex);
+ }
+#if ALS_DYN_INTT
+ if(epl_sensor.als.report_type == CMC_BIT_DYN_INT)
+ {
+ buf[0] = dynamic_intt_lux;
+ LOG_INFO("[%s]: als dynamic_intt_lux = %d \r\n", __func__, dynamic_intt_lux);
+ }
+ else
+#else
+ {
+ buf[0] = epl_sensor.als.data.channels[1];
+ LOG_INFO("[%s]: epl_sensor.als.data.channels[1] = %d \r\n", __func__, epl_sensor.als.data.channels[1]);
+ }
+#endif
+
+ if(copy_to_user(argp, &buf , sizeof(buf)))
+ return -EFAULT;
+
+ break;
+#endif
+#endif /*SPREAD MARVELL end......*/
+ default:
+ LOG_ERR("invalid cmd %d\n", _IOC_NR(cmd));
+ return -EINVAL;
+ }
+
+ return 0;
+
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct file_operations epl_sensor_ps_fops =
+{
+ .owner = THIS_MODULE,
+ .open = epl_sensor_ps_open,
+ .release = epl_sensor_ps_release,
+ .unlocked_ioctl = epl_sensor_ps_ioctl
+};
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct miscdevice epl_sensor_ps_device =
+{
+ .minor = MISC_DYNAMIC_MINOR,
+#if LEADCORE
+ .name = "proximity",
+#elif MARVELL
+ .name = "alps_pxy",
+#elif SPREAD
+ .name = "epl2182_pls",
+#endif
+ .fops = &epl_sensor_ps_fops
+};
+
+#if !(SPREAD || MARVELL) /*SPREAD MARVELL start.....*/
+/*----------------------------------------------------------------------------*/
+static ssize_t light_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_INFO("%s: ALS_status=%d\n", __func__, epld->enable_lflag);
+ return sprintf(buf, "%d\n", epld->enable_lflag);
+}
+
+static ssize_t light_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ uint16_t als_enable = 0;
+ LOG_INFO("light_enable_store: enable=%s \n", buf);
+
+ sscanf(buf, "%hu",&als_enable);
+
+ if(epld->enable_lflag != als_enable)
+ {
+ epld->enable_lflag = als_enable;
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ return size;
+}
+/*----------------------------------------------------------------------------*/
+static struct device_attribute dev_attr_light_enable =
+__ATTR(enable, S_IRWXUGO,
+ light_enable_show, light_enable_store);
+
+static struct attribute *light_sysfs_attrs[] = {
+ &dev_attr_light_enable.attr,
+ NULL
+};
+
+static struct attribute_group light_attribute_group = {
+ .attrs = light_sysfs_attrs,
+};
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_setup_lsensor(struct epl_sensor_priv *epld)
+{
+ int err = 0;
+ LOG_INFO("epl_sensor_setup_lsensor enter.\n");
+
+ epld->als_input_dev = input_allocate_device();
+ if (!epld->als_input_dev)
+ {
+ LOG_ERR( "could not allocate ls input device\n");
+ return -ENOMEM;
+ }
+ epld->als_input_dev->name = ElanALsensorName;
+ set_bit(EV_ABS, epld->als_input_dev->evbit);
+ input_set_abs_params(epld->als_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+ err = input_register_device(epld->als_input_dev);
+ if (err < 0)
+ {
+ LOG_ERR("can not register ls input device\n");
+ goto err_free_ls_input_device;
+ }
+
+ err = misc_register(&epl_sensor_als_device);
+ if (err < 0)
+ {
+ LOG_ERR("can not register ls misc device\n");
+ goto err_unregister_ls_input_device;
+ }
+
+ err = sysfs_create_group(&epld->als_input_dev->dev.kobj, &light_attribute_group);
+
+ if (err) {
+ pr_err("%s: could not create sysfs group\n", __func__);
+ goto err_free_ls_input_device;
+ }
+ return err;
+
+
+err_unregister_ls_input_device:
+ input_unregister_device(epld->als_input_dev);
+err_free_ls_input_device:
+ input_free_device(epld->als_input_dev);
+ return err;
+}
+#endif /*SPREAD MARVELL end.....*/
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static ssize_t proximity_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_INFO("%s: PS status=%d\n", __func__, epld->enable_pflag);
+ return sprintf(buf, "%d\n", epld->enable_pflag);
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static ssize_t proximity_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ uint16_t ps_enable = 0;
+#if HS_ENABLE
+ bool enable_hs = epld->enable_hflag==1 && epld->hs_suspend==0;
+#endif
+#if PS_GES
+ bool enable_ges = epld->enable_gflag==1 && epld->ges_suspend==0;
+#endif
+ LOG_INFO("proximity_enable_store: enable=%s \n", buf);
+
+ sscanf(buf, "%hu",&ps_enable);
+
+#if HS_ENABLE
+ if(enable_hs == 1 && ps_enable == 1)
+ {
+ epld->enable_hflag = 0;
+ if(hs_enable_flag == true)
+ {
+ epld->enable_lflag = 1;
+ hs_enable_flag = false;
+ }
+ write_global_variable(epld->client);
+ LOG_INFO("[%s] Disable HS and recover ps setting \r\n", __func__);
+ }
+#endif
+#if PS_GES
+ if(enable_ges == 1 && ps_enable == 1)
+ {
+ epld->enable_gflag = 0;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = true;
+ LOG_INFO("[%s] Disable GES and recover ps setting \r\n", __func__);
+ }
+ else if (ps_ges_enable_flag == true && ps_enable == 0)
+ {
+ epld->enable_gflag = 1;
+ write_global_variable(epld->client);
+ ps_ges_enable_flag = false;
+ LOG_INFO("[%s] enable GES and recover ges setting \r\n", __func__);
+ }
+#endif
+ if(epld->enable_pflag != ps_enable)
+ {
+ epld->enable_pflag = ps_enable;
+ if(ps_enable)
+ {
+ wake_lock(&ps_lock);
+#if PS_DYN_K
+ dynk_min_ps_raw_data = 0xffff;
+ dynk_change_flag = false;
+#if PS_DYN_K_STR
+ dynk_enhance_flag = false;
+#endif
+#endif
+ }
+ else
+ {
+#if PS_DYN_K
+ cancel_delayed_work(&dynk_thd_polling_work);
+#endif
+ wake_unlock(&ps_lock);
+ }
+
+ epl_sensor_update_mode(epld->client);
+ }
+
+ return size;
+}
+/*----------------------------------------------------------------------------*/
+static struct device_attribute dev_attr_psensor_enable =
+__ATTR(enable, S_IRWXUGO,
+ proximity_enable_show, proximity_enable_store);
+
+static struct attribute *proximity_sysfs_attrs[] = {
+ &dev_attr_psensor_enable.attr,
+ NULL
+};
+
+static struct attribute_group proximity_attribute_group = {
+ .attrs = proximity_sysfs_attrs,
+};
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_setup_psensor(struct epl_sensor_priv *epld)
+{
+ int err = 0;
+ LOG_INFO("epl_sensor_setup_psensor enter.\n");
+
+
+ epld->ps_input_dev = input_allocate_device();
+ if (!epld->ps_input_dev)
+ {
+ LOG_ERR("could not allocate ps input device\n");
+ return -ENOMEM;
+ }
+ epld->ps_input_dev->name = ElanPsensorName;
+
+ set_bit(EV_ABS, epld->ps_input_dev->evbit);
+ input_set_abs_params(epld->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);
+#if 1
+ set_bit(EV_ABS, epld->ps_input_dev->evbit);
+ input_set_abs_params(epld->ps_input_dev, ABS_MISC, 0, 9, 0, 0);
+#endif
+
+ err = input_register_device(epld->ps_input_dev);
+ if (err < 0)
+ {
+ LOG_ERR("could not register ps input device\n");
+ goto err_free_ps_input_device;
+ }
+
+ err = misc_register(&epl_sensor_ps_device);
+ if (err < 0)
+ {
+ LOG_ERR("could not register ps misc device\n");
+ goto err_unregister_ps_input_device;
+ }
+
+ err = sysfs_create_group(&epld->ps_input_dev->dev.kobj, &proximity_attribute_group);
+
+ if (err) {
+ pr_err("%s: PS could not create sysfs group\n", __func__);
+ goto err_free_ps_input_device;
+ }
+
+ return err;
+
+err_unregister_ps_input_device:
+ input_unregister_device(epld->ps_input_dev);
+err_free_ps_input_device:
+ input_free_device(epld->ps_input_dev);
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+#ifdef CONFIG_SUSPEND
+static int epl_sensor_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ epld->als_suspend=1;
+#if HS_ENABLE
+ epld->hs_suspend=1;
+#endif
+#if PS_GES
+ epld->ges_suspend = 1;
+ ps_ges_suspend_flag = true;
+#endif
+ if(epld->enable_pflag == 1){
+ //epld->ps_suspend=0;
+ LOG_INFO("[%s]: ps enable \r\n", __func__);
+ }
+ else{
+ //epld->ps_suspend=1;
+ LOG_INFO("[%s]: ps disable \r\n", __func__);
+ epl_sensor_update_mode(epld->client);
+ }
+
+ return 0;
+}
+
+static int epl_sensor_resume(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ epld->als_suspend=0;
+ epld->ps_suspend=0;
+#if HS_ENABLE
+ epld->hs_suspend=0;
+#endif
+#if PS_GES
+ epld->ges_suspend = 0;
+#endif
+ if(epld->enable_pflag == 1){
+ //epld->ps_suspend=0;
+ LOG_INFO("[%s]: ps enable \r\n", __func__);
+ epl_sensor_restart_polling();
+ }
+ else{
+ //epld->ps_suspend=1;
+ LOG_INFO("[%s]: ps disable \r\n", __func__);
+ epl_sensor_update_mode(epld->client);
+ }
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND) && PS_GES
+ ps_ges_suspend_flag = false;
+#endif
+ return 0;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+static void epl_sensor_early_suspend(struct early_suspend *h)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ epld->als_suspend=1;
+#if HS_ENABLE
+ epld->hs_suspend=1;
+#endif
+#if PS_GES
+ epld->ges_suspend = 1;
+ ps_ges_suspend_flag = true;
+#endif
+ if(epld->enable_pflag == 1)
+ {
+ //epld->ps_suspend=0;
+ LOG_INFO("[%s]: ps enable \r\n", __func__);
+ }
+ else
+ {
+ //epld->ps_suspend=1;
+ LOG_INFO("[%s]: ps disable \r\n", __func__);
+ epl_sensor_update_mode(epld->client);
+ }
+
+}
+
+static void epl_sensor_late_resume(struct early_suspend *h)
+{
+ struct epl_sensor_priv *epld = epl_sensor_obj;
+ LOG_FUN();
+
+ epld->als_suspend=0;
+ epld->ps_suspend=0;
+#if HS_ENABLE
+ epld->hs_suspend=0;
+#endif
+#if PS_GES
+ epld->ges_suspend = 0;
+#endif
+ if(epld->enable_pflag == 1){
+ //epld->ps_suspend=0;
+ LOG_INFO("[%s]: ps enable \r\n", __func__);
+ epl_sensor_restart_polling();
+ }
+ else{
+ //epld->ps_suspend=1;
+ LOG_INFO("[%s]: ps disable \r\n", __func__);
+ epl_sensor_update_mode(epld->client);
+ }
+#if PS_GES
+ ps_ges_suspend_flag = false;
+#endif
+}
+#endif
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_probe(struct i2c_client *client,const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct epl_sensor_priv *epld ;
+ struct elan_epl_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
+ LOG_INFO("elan sensor probe enter.\n");
+
+#ifdef CONFIG_OF
+ if (np && !pdata){
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Could not allocate struct elan_epl_platform_data");
+ goto exit_allocate_pdata_failed;
+ }
+ pdata->irq_gpio_number = of_get_gpio(np, 0);
+ if(pdata->irq_gpio_number < 0){
+ dev_err(&client->dev, "fail to get irq_gpio_number\n");
+ kfree(pdata);
+ goto exit_irq_gpio_read_fail;
+ }
+ client->dev.platform_data = pdata;
+ }
+#endif
+
+ epld = kzalloc(sizeof(struct epl_sensor_priv), GFP_KERNEL);
+ if (!epld)
+ return -ENOMEM;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ {
+ dev_err(&client->dev,"No supported i2c func what we need?!!\n");
+ err = -ENOTSUPP;
+ goto i2c_fail;
+ }
+ LOG_INFO("chip id REG 0x00 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x00));
+ LOG_INFO("chip id REG 0x01 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x01));
+ LOG_INFO("chip id REG 0x02 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x02));
+ LOG_INFO("chip id REG 0x03 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x03));
+ LOG_INFO("chip id REG 0x04 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x04));
+ LOG_INFO("chip id REG 0x05 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x05));
+ LOG_INFO("chip id REG 0x06 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x06));
+ LOG_INFO("chip id REG 0x07 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x07));
+ LOG_INFO("chip id REG 0x11 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x11));
+ LOG_INFO("chip id REG 0x12 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x12));
+ LOG_INFO("chip id REG 0x1B value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x1B));
+ LOG_INFO("chip id REG 0x20 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x20));
+ LOG_INFO("chip id REG 0x21 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x21));
+ LOG_INFO("chip id REG 0x24 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x24));
+ LOG_INFO("chip id REG 0x25 value = 0x%x\n", i2c_smbus_read_byte_data(client, 0x25));
+
+ if((i2c_smbus_read_byte_data(client, 0x21)) != 0x81){
+ LOG_INFO("elan ALS/PS sensor is failed. \n");
+ goto i2c_fail;
+ }
+
+ epld->als_level_num = sizeof(epld->als_level)/sizeof(epld->als_level[0]);
+ epld->als_value_num = sizeof(epld->als_value)/sizeof(epld->als_value[0]);
+ BUG_ON(sizeof(epld->als_level) != sizeof(als_level));
+ memcpy(epld->als_level, als_level, sizeof(epld->als_level));
+ BUG_ON(sizeof(epld->als_value) != sizeof(als_value));
+ memcpy(epld->als_value, als_value, sizeof(epld->als_value));
+
+ epld->client = client;
+ this_client = client;
+ epld->intr_pin= pdata->irq_gpio_number;
+
+#if HS_ENABLE
+ epld->hs_suspend = 0;
+ mutex_init(&hs_sensor_mutex);
+#endif
+#if PS_GES
+ epld->ges_suspend = 0;
+ epld->gs_input_dev = input_allocate_device();
+ set_bit(EV_KEY, epld->gs_input_dev->evbit);
+ set_bit(EV_REL, epld->gs_input_dev->evbit);
+ set_bit(EV_ABS, epld->gs_input_dev->evbit);
+ epld->gs_input_dev->evbit[0] |= BIT_MASK(EV_REP);
+ epld->gs_input_dev->keycodemax = 500;
+ epld->gs_input_dev->name ="elan_gesture";
+ epld->gs_input_dev->keybit[BIT_WORD(KEYCODE_LEFT)] |= BIT_MASK(KEYCODE_LEFT);
+ if (input_register_device(epld->gs_input_dev))
+ LOG_ERR("register input error\n");
+#endif
+ i2c_set_clientdata(client, epld);
+
+ epl_sensor_obj = epld;
+
+ INIT_DELAYED_WORK(&epld->eint_work, epl_sensor_eint_work);
+
+ epld->epl_wq = create_workqueue("epl2182_pls"); //create_singlethread_workqueue
+ if (!epld->epl_wq)
+ {
+ LOG_ERR("can't create workqueue\n");
+ err = -ENOMEM;
+ goto err_create_singlethread_workqueue;
+ }
+
+ mutex_init(&sensor_mutex);
+
+ //initial global variable and write to senosr
+ initial_global_variable(client, epld);
+#if !(SPREAD || MARVELL)
+ err = epl_sensor_setup_lsensor(epld);
+ if (err < 0)
+ {
+ LOG_ERR("epl_sensor_setup_lsensor error!!\n");
+ goto err_lightsensor_setup;
+ }
+#endif
+
+ err = epl_sensor_setup_psensor(epld);
+ if (err < 0)
+ {
+ LOG_ERR("epl_sensor_setup_psensor error!!\n");
+ goto err_psensor_setup;
+ }
+
+
+ if (epl_sensor.als.polling_mode==0 || epl_sensor.ps.polling_mode==0)
+ {
+ err = epl_sensor_setup_interrupt(epld);
+ if (err < 0)
+ {
+ LOG_ERR("setup error!\n");
+ goto err_sensor_setup;
+ }
+ }
+ //disable_irq(epld->irq); //ices add
+
+#ifdef CONFIG_SUSPEND
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ epld->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ epld->early_suspend.suspend = epl_sensor_early_suspend;
+ epld->early_suspend.resume = epl_sensor_late_resume;
+ register_early_suspend(&epld->early_suspend);
+#endif
+
+#endif
+
+ wake_lock_init(&ps_lock, WAKE_LOCK_SUSPEND, "ps wakelock");
+#if 0
+ sensor_dev = platform_device_register_simple("elan_alsps", -1, NULL, 0);
+ if (IS_ERR(sensor_dev))
+ {
+ printk ("sensor_dev_init: error\n");
+ goto err_fail;
+ }
+
+
+ err = sysfs_create_group(&sensor_dev->dev.kobj, &epl_sensor_attr_group);
+ if (err !=0)
+ {
+ dev_err(&client->dev,"%s:create sysfs group error", __func__);
+ goto err_fail;
+ }
+#endif
+ LOG_INFO("sensor probe success.\n");
+ return err;
+
+err_fail:
+ input_unregister_device(epld->als_input_dev);
+ input_unregister_device(epld->ps_input_dev);
+ input_free_device(epld->als_input_dev);
+ input_free_device(epld->ps_input_dev);
+#if !(SPREAD || MARVELL)
+err_lightsensor_setup:
+#endif
+err_psensor_setup:
+err_sensor_setup:
+ destroy_workqueue(epld->epl_wq);
+ misc_deregister(&epl_sensor_ps_device);
+#if !(SPREAD || MARVELL)
+ misc_deregister(&epl_sensor_als_device);
+#endif
+err_create_singlethread_workqueue:
+i2c_fail:
+ kfree(epld);
+#ifdef CONFIG_OF
+exit_irq_gpio_read_fail:
+exit_allocate_pdata_failed:
+#endif
+
+ return err;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static int epl_sensor_remove(struct i2c_client *client)
+{
+ struct epl_sensor_priv *epld = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s: enter.\n", __func__);
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&epld->early_suspend);
+#endif
+ sysfs_remove_group(&sensor_dev->dev.kobj, &epl_sensor_attr_group);
+ platform_device_unregister(sensor_dev);
+ input_unregister_device(epld->als_input_dev);
+ input_unregister_device(epld->ps_input_dev);
+#if !(SPREAD || MARVELL)
+ input_free_device(epld->als_input_dev);
+#endif
+ input_free_device(epld->ps_input_dev);
+ misc_deregister(&epl_sensor_ps_device);
+#if !(SPREAD || MARVELL)
+ misc_deregister(&epl_sensor_als_device);
+#endif
+ free_irq(epld->irq,epld);
+ destroy_workqueue(epld->epl_wq);
+ kfree(epld);
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static const struct i2c_device_id epl_sensor_id[] =
+{
+ { EPL_DEV_NAME, 0 },
+ {}
+};
+
+#if SPREAD
+static struct of_device_id epl_match_table[] = {
+ { .compatible = "ELAN,epl259x_pls", },
+ {}
+};
+#endif
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+static struct i2c_driver epl_sensor_driver =
+{
+ .probe = epl_sensor_probe,
+ .remove = epl_sensor_remove,
+ .id_table = epl_sensor_id,
+ .driver = {
+ .name = EPL_DEV_NAME,
+ .owner = THIS_MODULE,
+#if SPREAD
+ .of_match_table =epl_match_table,
+#endif
+ },
+#ifdef CONFIG_SUSPEND
+ //.suspend = epl_sensor_suspend,
+ //.resume = epl_sensor_resume,
+#endif
+};
+
+static int __init epl_sensor_init(void)
+{
+ return i2c_add_driver(&epl_sensor_driver);
+}
+
+static void __exit epl_sensor_exit(void)
+{
+ i2c_del_driver(&epl_sensor_driver);
+}
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+module_init(epl_sensor_init);
+module_exit(epl_sensor_exit);
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+MODULE_AUTHOR("Renato Pan <renato.pan@eminent-tek.com>");
+MODULE_DESCRIPTION("ELAN epl259x driver");
+MODULE_LICENSE("GPL");