From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/input/misc/stk3x1x.c | 4262 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4262 insertions(+) create mode 100644 drivers/input/misc/stk3x1x.c (limited to 'drivers/input/misc/stk3x1x.c') diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c new file mode 100644 index 00000000..a6ed55fb --- /dev/null +++ b/drivers/input/misc/stk3x1x.c @@ -0,0 +1,4262 @@ +/* + * stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x, stk331x + * , and stk3410 proximity/ambient light sensor + * + * Copyright (C) 2012~2015 Lex Hsieh / sensortek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +//#include +#include + +#include + +#define DRIVER_VERSION "3.10.1 20151217" + +/* Driver Settings */ +#define CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD +#ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD +#define STK_ALS_CHANGE_THD 5 //10 /* The threshold to trigger ALS interrupt, unit: lux */ +#endif /* #ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD */ +#define STK_INT_PS_MODE 1 /* 1, 2, or 3 */ +//#define STK_POLL_PS +#define STK_POLL_ALS /* ALS interrupt is valid only when STK_INT_PS_MODE = 1 or 4*/ +#define STK_TUNE0 +#define CALI_PS_EVERY_TIME +//#define STK_DEBUG_PRINTF +#define SPREADTRUM_PLATFORM +#define STK_ALS_FIR +//#define STK_IRS +//#define STK_CHK_REG +//#define STK_GES +//#define STK_QUALCOMM_POWER_CTRL +//#define QUALCOMM_PLATFORM + +#if 0 +#ifdef SPREADTRUM_PLATFORM +#include +#else + #include "stk3x1x.h" +#endif +#endif +#include "stk3x1x.h" + +/* Define Register Map */ +#define STK_STATE_REG 0x00 +#define STK_PSCTRL_REG 0x01 +#define STK_ALSCTRL_REG 0x02 +#define STK_LEDCTRL_REG 0x03 +#define STK_INT_REG 0x04 +#define STK_WAIT_REG 0x05 +#define STK_THDH1_PS_REG 0x06 +#define STK_THDH2_PS_REG 0x07 +#define STK_THDL1_PS_REG 0x08 +#define STK_THDL2_PS_REG 0x09 +#define STK_THDH1_ALS_REG 0x0A +#define STK_THDH2_ALS_REG 0x0B +#define STK_THDL1_ALS_REG 0x0C +#define STK_THDL2_ALS_REG 0x0D +#define STK_FLAG_REG 0x10 +#define STK_DATA1_PS_REG 0x11 +#define STK_DATA2_PS_REG 0x12 +#define STK_DATA1_ALS_REG 0x13 +#define STK_DATA2_ALS_REG 0x14 +#define STK_DATA1_OFFSET_REG 0x15 +#define STK_DATA2_OFFSET_REG 0x16 +#define STK_DATA1_IR_REG 0x17 +#define STK_DATA2_IR_REG 0x18 +#define STK_PDT_ID_REG 0x3E +#define STK_RSRVD_REG 0x3F +#define STK_SW_RESET_REG 0x80 + +#define STK_GSCTRL_REG 0x1A +#define STK_FLAG2_REG 0x1C + +/* Define state reg */ +#define STK_STATE_EN_IRS_SHIFT 7 +#define STK_STATE_EN_AK_SHIFT 6 +#define STK_STATE_EN_ASO_SHIFT 5 +#define STK_STATE_EN_IRO_SHIFT 4 +#define STK_STATE_EN_WAIT_SHIFT 2 +#define STK_STATE_EN_ALS_SHIFT 1 +#define STK_STATE_EN_PS_SHIFT 0 + +#define STK_STATE_EN_IRS_MASK 0x80 +#define STK_STATE_EN_AK_MASK 0x40 +#define STK_STATE_EN_ASO_MASK 0x20 +#define STK_STATE_EN_IRO_MASK 0x10 +#define STK_STATE_EN_WAIT_MASK 0x04 +#define STK_STATE_EN_ALS_MASK 0x02 +#define STK_STATE_EN_PS_MASK 0x01 + +/* Define PS ctrl reg */ +#define STK_PS_PRS_SHIFT 6 +#define STK_PS_GAIN_SHIFT 4 +#define STK_PS_IT_SHIFT 0 + +#define STK_PS_PRS_MASK 0xC0 +#define STK_PS_GAIN_MASK 0x30 +#define STK_PS_IT_MASK 0x0F + +/* Define ALS ctrl reg */ +#define STK_ALS_PRS_SHIFT 6 +#define STK_ALS_GAIN_SHIFT 4 +#define STK_ALS_IT_SHIFT 0 + +#define STK_ALS_PRS_MASK 0xC0 +#define STK_ALS_GAIN_MASK 0x30 +#define STK_ALS_IT_MASK 0x0F + +/* Define LED ctrl reg */ +#define STK_LED_IRDR_SHIFT 6 +#define STK_LED_DT_SHIFT 0 + +#define STK_LED_IRDR_MASK 0xC0 +#define STK_LED_DT_MASK 0x3F + +/* Define interrupt reg */ +#define STK_INT_CTRL_SHIFT 7 +#define STK_INT_OUI_SHIFT 4 +#define STK_INT_ALS_SHIFT 3 +#define STK_INT_PS_SHIFT 0 + +#define STK_INT_CTRL_MASK 0x80 +#define STK_INT_OUI_MASK 0x10 +#define STK_INT_ALS_MASK 0x08 +#define STK_INT_PS_MASK 0x07 + +#define STK_INT_ALS 0x08 + +/* Define flag reg */ +#define STK_FLG_ALSDR_SHIFT 7 +#define STK_FLG_PSDR_SHIFT 6 +#define STK_FLG_ALSINT_SHIFT 5 +#define STK_FLG_PSINT_SHIFT 4 +#define STK_FLG_OUI_SHIFT 2 +#define STK_FLG_IR_RDY_SHIFT 1 +#define STK_FLG_NF_SHIFT 0 + +#define STK_FLG_ALSDR_MASK 0x80 +#define STK_FLG_PSDR_MASK 0x40 +#define STK_FLG_ALSINT_MASK 0x20 +#define STK_FLG_PSINT_MASK 0x10 +#define STK_FLG_OUI_MASK 0x04 +#define STK_FLG_IR_RDY_MASK 0x02 +#define STK_FLG_NF_MASK 0x01 + +/* Define flag2 reg */ +#define STK_FLG2_INT_GS_SHIFT 6 +#define STK_FLG2_GS10_SHIFT 5 +#define STK_FLG2_GS01_SHIFT 4 + +#define STK_FLG2_INT_GS_MASK 0x40 +#define STK_FLG2_GS10_MASK 0x20 +#define STK_FLG2_GS01_MASK 0x10 + + +/* misc define */ +#define MIN_ALS_POLL_DELAY_NS 60000000 + + +#ifdef STK_TUNE0 + #define STK_MAX_MIN_DIFF 150 //200 + #define STK_LT_N_CT 50 //100 + #define STK_HT_N_CT 80 //150 +#endif /* #ifdef STK_TUNE0 */ + +#define STK_IRC_MAX_ALS_CODE 20000 +#define STK_IRC_MIN_ALS_CODE 25 +#define STK_IRC_MIN_IR_CODE 50 +#define STK_IRC_ALS_DENOMI 2 +#define STK_IRC_ALS_NUMERA 5 +#define STK_IRC_ALS_CORREC 850 + +#define STK_IRS_IT_REDUCE 2 +#define STK_ALS_READ_IRS_IT_REDUCE 5 +#define STK_ALS_THRESHOLD 30 + +#define DEVICE_NAME "stk_ps" +#define ALS_NAME "lightsensor-level" +#define PS_NAME "proximity" + +#ifdef STK_QUALCOMM_POWER_CTRL + /* POWER SUPPLY VOLTAGE RANGE */ + #define STK3X1X_VDD_MIN_UV 2000000 + #define STK3X1X_VDD_MAX_UV 3300000 + #define STK3X1X_VIO_MIN_UV 1750000 + #define STK3X1X_VIO_MAX_UV 1950000 +#endif + +#define STK3310SA_PID 0x17 +#define STK3311SA_PID 0x1E +#define STK3311WV_PID 0x1D + +#ifdef SPREADTRUM_PLATFORM +extern int sprd_3rdparty_gpio_pls_irq; + +static struct stk3x1x_platform_data stk3x1x_pfdata={ + .state_reg = 0x0, /* disable all */ + .psctrl_reg = 0x31, /* ps_persistance=1, ps_gain=64X, PS_IT=0.391ms */ + .alsctrl_reg = 0x39, /* als_persistance=1, als_gain=64X, ALS_IT=100ms */ + .ledctrl_reg = 0xFF, /* 100mA IRDR, 64/64 LED duty */ + .wait_reg = 0xF, /* 100 ms */ + .ps_thd_h =1700, + .ps_thd_l = 1500, + .int_pin = 216,//GPIO_PROX_INT//sprd_3rdparty_gpio_pls_irq + .transmittance = 3100, //500 +}; +#endif + +#ifdef STK_ALS_FIR + #define STK_FIR_LEN 4 //6 //8 + #define MAX_FIR_LEN 32 +struct data_filter { + u16 raw[MAX_FIR_LEN]; + int sum; + int number; + int idx; +}; +#endif + +#ifdef STK_GES +union stk_ges_operation{ + uint8_t ops[4]; + struct { + uint8_t rw_len_retry; + uint8_t reg; + uint8_t reg_value_retry_crit; + uint8_t sleep_10ns; + }action; +}; + +union stk_ges_operation stk_ges_op[10] = +{ + {.ops={0xc1, 0x24, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}}, + {.ops={0, 0, 0, 0}} +}; +#endif + +struct stk3x1x_data { + struct i2c_client *client; + struct stk3x1x_platform_data *pdata; +#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) + int32_t irq; + struct work_struct stk_work; + struct workqueue_struct *stk_wq; +#endif + uint16_t ir_code; + uint16_t als_correct_factor; + uint8_t alsctrl_reg; + uint8_t psctrl_reg; + uint8_t ledctrl_reg; + uint8_t state_reg; + int int_pin; + uint8_t wait_reg; + uint8_t int_reg; +#ifdef CONFIG_HAS_EARLYSUSPEND + //struct early_suspend stk_early_suspend; +#endif + uint16_t ps_thd_h; + uint16_t ps_thd_l; +#ifdef CALI_PS_EVERY_TIME + uint16_t ps_high_thd_boot; + uint16_t ps_low_thd_boot; +#endif + struct mutex io_lock; + struct input_dev *ps_input_dev; + int32_t ps_distance_last; + bool ps_enabled; + bool re_enable_ps; + struct wake_lock ps_wakelock; +#ifdef STK_POLL_PS + struct hrtimer ps_timer; + struct work_struct stk_ps_work; + struct workqueue_struct *stk_ps_wq; + struct wake_lock ps_nosuspend_wl; +#endif + struct input_dev *als_input_dev; + int32_t als_lux_last; + uint32_t als_transmittance; + bool als_enabled; + bool re_enable_als; + ktime_t ps_poll_delay; + ktime_t als_poll_delay; +#ifdef STK_POLL_ALS + struct work_struct stk_als_work; + struct hrtimer als_timer; + struct workqueue_struct *stk_als_wq; +#endif + bool first_boot; +#ifdef STK_TUNE0 + uint16_t psa; + uint16_t psi; + uint16_t psi_set; + struct hrtimer ps_tune0_timer; + struct workqueue_struct *stk_ps_tune0_wq; + struct work_struct stk_ps_tune0_work; + ktime_t ps_tune0_delay; + bool tune_zero_init_proc; + uint32_t ps_stat_data[3]; + int data_count; + int stk_max_min_diff; + int stk_lt_n_ct; + int stk_ht_n_ct; +#endif +#ifdef STK_ALS_FIR + struct data_filter fir; + atomic_t firlength; +#endif + atomic_t recv_reg; + +#ifdef STK_GES + struct input_dev *ges_input_dev; + int ges_enabled; + int re_enable_ges; + atomic_t gesture2; +#endif +#ifdef STK_IRS + int als_data_index; +#endif +#ifdef STK_QUALCOMM_POWER_CTRL + struct regulator *vdd; + struct regulator *vio; + bool power_enabled; +#endif + uint8_t pid; + uint8_t p_wv_r_bd_with_co; + uint32_t als_code_last; +}; + +#if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD)) +static uint32_t lux_threshold_table[] = +{ + 3, + 10, + 40, + 65, + 145, + 300, + 550, + 930, + 1250, + 1700, +}; + +#define LUX_THD_TABLE_SIZE (sizeof(lux_threshold_table)/sizeof(uint32_t)+1) +static uint16_t code_threshold_table[LUX_THD_TABLE_SIZE+1]; +#endif + +static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable, uint8_t validate_reg); +static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable); +static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l); +static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h); +static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l); +static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h); +static int32_t stk3x1x_get_ir_reading(struct stk3x1x_data *ps_data, int32_t als_it_reduce); +#ifdef STK_TUNE0 +static int stk_ps_tune_zero_func_fae(struct stk3x1x_data *ps_data); +#endif +#ifdef STK_CHK_REG +static int stk3x1x_validate_n_handle(struct i2c_client *client); +#endif +static int stk_ps_val(struct stk3x1x_data *ps_data); +#ifdef STK_QUALCOMM_POWER_CTRL +static int stk3x1x_device_ctl(struct stk3x1x_data *ps_data, bool enable); +#endif + +static int stk3x1x_i2c_read_data(struct i2c_client *client, unsigned char command, int length, unsigned char *values) +{ + uint8_t retry; + int err; + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = values, + }, + }; + + for (retry = 0; retry < 5; retry++) + { + err = i2c_transfer(client->adapter, msgs, 2); + if (err == 2) + break; + else + mdelay(5); + } + //printk("stk3x1x_i2c_read_data"); + + if (retry >= 5) + { + printk(KERN_ERR "%s: i2c read fail, err=%d\n", __func__, err); + return -EIO; + } + return 0; +} + +static int stk3x1x_i2c_write_data(struct i2c_client *client, unsigned char command, int length, unsigned char *values) +{ + int retry; + int err; + unsigned char data[11]; + struct i2c_msg msg; + int index; + //printk("stk3x1x_i2c_write_data"); + + if (!client) + return -EINVAL; + else if (length >= 10) + { + printk(KERN_ERR "%s:length %d exceeds 10\n", __func__, length); + return -EINVAL; + } + + data[0] = command; + for (index=1;index<=length;index++) + data[index] = values[index-1]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = length+1; + msg.buf = data; + + for (retry = 0; retry < 5; retry++) + { + err = i2c_transfer(client->adapter, &msg, 1); + if (err == 1) + break; + else + mdelay(5); + } + + if (retry >= 5) + { + printk(KERN_ERR "%s: i2c write fail, err=%d\n", __func__, err); + return -EIO; + } + return 0; +} + +static int stk3x1x_i2c_smbus_read_byte_data(struct i2c_client *client, unsigned char command) +{ + unsigned char value; + int err; + err = stk3x1x_i2c_read_data(client, command, 1, &value); + if(err < 0) + return err; + return value; +} + +static int stk3x1x_i2c_smbus_write_byte_data(struct i2c_client *client, unsigned char command, unsigned char value) +{ + int err; + err = stk3x1x_i2c_write_data(client, command, 1, &value); + return err; +} + +uint32_t stk_alscode2lux(struct stk3x1x_data *ps_data, uint32_t alscode) +{ + alscode += ((alscode<<7)+(alscode<<3)+(alscode>>1)); + alscode<<=3; + alscode/=ps_data->als_transmittance; + return alscode; +} + +uint32_t stk_lux2alscode(struct stk3x1x_data *ps_data, uint32_t lux) +{ + lux*=ps_data->als_transmittance; + lux/=1100; + if (unlikely(lux>=(1<<16))) + lux = (1<<16) -1; + return lux; +} + +#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD +static void stk_init_code_threshold_table(struct stk3x1x_data *ps_data) +{ + uint32_t i,j; + uint32_t alscode; + + code_threshold_table[0] = 0; +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "alscode[0]=%d\n",0); +#endif + for (i=1,j=0;i=code_threshold_table[i-1])&&(alscode= (1<<16)) + high_thd = (1<<16) -1; + if (low_thd <0) + low_thd = 0; + stk3x1x_set_als_thd_h(ps_data, (uint16_t)high_thd); + stk3x1x_set_als_thd_l(ps_data, (uint16_t)low_thd); +} +#endif // CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD + + +static void stk3x1x_proc_plat_data(struct stk3x1x_data *ps_data, struct stk3x1x_platform_data *plat_data) +{ + uint8_t w_reg; + + ps_data->state_reg = plat_data->state_reg; + ps_data->psctrl_reg = plat_data->psctrl_reg; +#ifdef STK_POLL_PS + ps_data->psctrl_reg &= 0x3F; +#endif + ps_data->alsctrl_reg = plat_data->alsctrl_reg; + ps_data->ledctrl_reg = plat_data->ledctrl_reg; + if(ps_data->pid == STK3310SA_PID || ps_data->pid == STK3311SA_PID) + ps_data->ledctrl_reg &= 0x3F; + + ps_data->wait_reg = plat_data->wait_reg; + if(ps_data->wait_reg < 2) + { + printk(KERN_WARNING "%s: wait_reg should be larger than 2, force to write 2\n", __func__); + ps_data->wait_reg = 2; + } + else if (ps_data->wait_reg > 0xFF) + { + printk(KERN_WARNING "%s: wait_reg should be less than 0xFF, force to write 0xFF\n", __func__); + ps_data->wait_reg = 0xFF; + } +//#ifndef STK_TUNE0 + if(ps_data->ps_thd_h == 0 && ps_data->ps_thd_l == 0) + { + ps_data->ps_thd_h = plat_data->ps_thd_h; + ps_data->ps_thd_l = plat_data->ps_thd_l; + } +//#endif +#ifdef CALI_PS_EVERY_TIME + ps_data->ps_high_thd_boot = plat_data->ps_thd_h; + ps_data->ps_low_thd_boot = plat_data->ps_thd_l; +#endif + w_reg = 0; +#ifndef STK_POLL_PS + w_reg |= STK_INT_PS_MODE; +#else + w_reg |= 0x01; +#endif + +#if (!defined(STK_POLL_ALS) && (STK_INT_PS_MODE != 0x02) && (STK_INT_PS_MODE != 0x03)) + w_reg |= STK_INT_ALS; +#endif + ps_data->int_reg = w_reg; + return; +} + +static int32_t stk3x1x_init_all_reg(struct stk3x1x_data *ps_data) +{ + int32_t ret; + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, ps_data->state_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_PSCTRL_REG, ps_data->psctrl_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, ps_data->alsctrl_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_LEDCTRL_REG, ps_data->ledctrl_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, ps_data->wait_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } +#ifdef STK_TUNE0 + ps_data->psa = 0x0; + ps_data->psi = 0xFFFF; +#endif +//#else + stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); + stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); +//#endif + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, ps_data->int_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + /* + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, 0x87, 0x60); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + */ + + return 0; +} + +static int32_t stk3x1x_read_otp25(struct stk3x1x_data *ps_data) +{ + int32_t ret, otp25; + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, 0x0, 0x2); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, 0x90, 0x25); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, 0x92, 0x82); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + usleep_range(1000, 5000); + + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,0x91); + if (ret < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; + } + otp25 = ret; + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, 0x0, 0x0); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + printk(KERN_INFO "%s: otp25=0x%x\n", __func__, otp25); + if(otp25 & 0x80) + return 1; + return 0; +} + +static int32_t stk3x1x_check_pid(struct stk3x1x_data *ps_data) +{ + unsigned char value[2], pid_msb; + int err; + + ps_data->p_wv_r_bd_with_co = 0; + + err = stk3x1x_i2c_read_data(ps_data->client, STK_PDT_ID_REG, 2, &value[0]); + if(err < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, err); + return err; + } + + printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, value[0], value[1]); + ps_data->pid = value[0]; + + if(value[0] == STK3311WV_PID) + ps_data->p_wv_r_bd_with_co |= 0b100; + if(value[1] == 0xC3) + ps_data->p_wv_r_bd_with_co |= 0b010; + + if(stk3x1x_read_otp25(ps_data) == 1) + { + ps_data->p_wv_r_bd_with_co |= 0b001; + } + printk(KERN_INFO "%s: p_wv_r_bd_with_co = 0x%x\n", __func__, ps_data->p_wv_r_bd_with_co); + + if(value[0] == 0) + { + printk(KERN_ERR "PID=0x0, please make sure the chip is stk3x1x!\n"); + return -2; + } + + pid_msb = value[0] & 0xF0; + switch(pid_msb) + { + case 0x10: + case 0x20: + case 0x30: + return 0; + default: + printk(KERN_ERR "%s: invalid PID(%#x)\n", __func__, value[0]); + return -1; + } + return 0; +} + + +static int32_t stk3x1x_software_reset(struct stk3x1x_data *ps_data) +{ + int32_t r; + uint8_t w_reg; + + w_reg = 0x7F; + r = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_WAIT_REG,w_reg); + if (r<0) + { + printk(KERN_ERR "%s: software reset: write i2c error, ret=%d\n", __func__, r); + return r; + } + r = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_WAIT_REG); + if (w_reg != r) + { + printk(KERN_ERR "%s: software reset: read-back value is not the same\n", __func__); + return -1; + } + + r = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_SW_RESET_REG,0); + if (r<0) + { + printk(KERN_ERR "%s: software reset: read error after reset\n", __func__); + return r; + } + usleep_range(13000, 15000); + return 0; +} + + +static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l) +{ + unsigned char val[2]; + int ret; + val[0] = (thd_l & 0xFF00) >> 8; + val[1] = thd_l & 0x00FF; + ret = stk3x1x_i2c_write_data(ps_data->client, STK_THDL1_ALS_REG, 2, val); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} +static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h) +{ + unsigned char val[2]; + int ret; + val[0] = (thd_h & 0xFF00) >> 8; + val[1] = thd_h & 0x00FF; + ret = stk3x1x_i2c_write_data(ps_data->client, STK_THDH1_ALS_REG, 2, val); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l) +{ + unsigned char val[2]; + int ret; + val[0] = (thd_l & 0xFF00) >> 8; + val[1] = thd_l & 0x00FF; + ret = stk3x1x_i2c_write_data(ps_data->client, STK_THDL1_PS_REG, 2, val); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} +static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h) +{ + unsigned char val[2]; + int ret; + val[0] = (thd_h & 0xFF00) >> 8; + val[1] = thd_h & 0x00FF; + ret = stk3x1x_i2c_write_data(ps_data->client, STK_THDH1_PS_REG, 2, val); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static uint32_t stk3x1x_get_ps_reading(struct stk3x1x_data *ps_data) +{ + unsigned char value[2]; + int err; + err = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_PS_REG, 2, &value[0]); + if(err < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, err); + return err; + } + return ((value[0]<<8) | value[1]); +} + + +static int32_t stk3x1x_set_flag(struct stk3x1x_data *ps_data, uint8_t org_flag_reg, uint8_t clr) +{ + uint8_t w_flag; + int ret; + + w_flag = org_flag_reg | (STK_FLG_ALSINT_MASK | STK_FLG_PSINT_MASK | STK_FLG_OUI_MASK | STK_FLG_IR_RDY_MASK); + w_flag &= (~clr); + //printk(KERN_INFO "%s: org_flag_reg=0x%x, w_flag = 0x%x\n", __func__, org_flag_reg, w_flag); + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_FLAG_REG, w_flag); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static int32_t stk3x1x_get_flag(struct stk3x1x_data *ps_data) +{ + int ret; + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_FLAG_REG); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +#ifdef STK_GES +static int32_t stk3x1x_set_flag2(struct stk3x1x_data *ps_data, uint8_t org_flag2_reg, uint8_t clr) +{ + uint8_t w_flag2; + int ret; + + w_flag2 = org_flag2_reg | 0x72; + w_flag2 &= (~clr); + //printk(KERN_INFO "%s: org_flag2_reg=0x%x, w_flag2 = 0x%x\n", __func__, org_flag2_reg, w_flag2); + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_FLAG2_REG, w_flag2); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static int32_t stk3x1x_get_flag2(struct stk3x1x_data *ps_data) +{ + int ret; + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_FLAG2_REG); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} +#endif + +static int32_t stk3x1x_set_state(struct stk3x1x_data *ps_data, uint8_t state) +{ + int ret; + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_STATE_REG, state); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static int32_t stk3x1x_get_state(struct stk3x1x_data *ps_data) +{ + int ret; + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +#ifdef STK_GES +static int32_t stk3x1x_set_gsctrl(struct stk3x1x_data *ps_data, uint8_t state) +{ + int ret; + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client,STK_GSCTRL_REG, state); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +static int32_t stk3x1x_get_gsctrl(struct stk3x1x_data *ps_data) +{ + int ret; + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_GSCTRL_REG); + if(ret < 0) + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, ret); + return ret; +} + +#if 0 +static uint32_t stk3x1x_get_ges_reading(struct stk3x1x_data *ps_data, unsigned int *ges0, + unsigned int *ges1, unsigned int *ges2) +{ + int retry, len, no = 0; + uint8_t reg_val_crit; + int err; + unsigned char value[10]; + + while(stk_ges_op[no].ops[1] != 0) + { + retry = stk_ges_op[no].action.rw_len_retry & 0x0F; + len = (stk_ges_op[no].action.rw_len_retry & 0x70) >> 4; + reg_val_crit = stk_ges_op[no].action.reg_value_retry_crit; + if(stk_ges_op[no].action.rw_len_retry & 0x80) + { + while(retry != 0) + { + err = stk3x1x_i2c_read_data(ps_data->client, + stk_ges_op[no].action.reg, len, value); + if(err < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, err); + return err; + } + if(reg_val_crit) + { + if(value[0] & reg_val_crit) + break; + } + if(stk_ges_op[no].action.sleep_10ns != 0) + usleep_range(stk_ges_op[no].action.sleep_10ns*10, + stk_ges_op[no].action.sleep_10ns*10+300); + retry--; + } + } + else + { + while(retry != 0) + { + err = stk3x1x_i2c_write_data(ps_data->client, stk_ges_op[no].action.reg, + len, ®_val_crit); + if(err < 0) + { + printk(KERN_ERR "%s: fail, err=%d\n", __func__, err); + return err; + } + + if(stk_ges_op[no].action.sleep_10ns != 0) + usleep_range(stk_ges_op[no].action.sleep_10ns*10, + stk_ges_op[no].action.sleep_10ns*10+300); + retry--; + } + } + + if(stk_ges_op[no].action.reg == 0x24) + { + *ges0 = (value[0]<<8) | value[1]; + *ges1 = (value[2]<<8) | value[3]; + } + else if(stk_ges_op[no].action.reg == stk_ges_op[9].ops[0]) + { + *ges2 = (value[0]<<8) | value[1]; + } + + no++; + } + return 0; +} + +#else +static uint32_t stk3x1x_get_ges_reading(struct stk3x1x_data *ps_data, unsigned int *ges0,unsigned int *ges1,unsigned int *ges2) +{ + unsigned char value[4]; + int err, retry = 10; + + do { + err = stk3x1x_get_flag(ps_data); + if(err < 0) + return err; + if(err & STK_FLG_PSDR_MASK) + break; + //printk(KERN_INFO "ges: not ready, %d\n", retry); + retry--; + usleep_range(350, 1000); + } while(retry > 0); + err = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_PS_REG, 2, &value[0]); + + err = stk3x1x_i2c_read_data(ps_data->client, 0x24, 4, &value[0]); + if(err < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, err); + return err; + } + *ges0 = (value[0]<<8) | value[1]; + *ges1 = (value[2]<<8) | value[3]; + //printk(KERN_INFO "%s: ges=%d,%d\n",__func__, *ges0, *ges1); + return 0; +} +#endif + +static int32_t stk3x1x_enable_ges(struct stk3x1x_data *ps_data, uint8_t enable, uint8_t mode) +{ + int32_t ret; + uint8_t w_state_reg, gsctrl_reg; + uint8_t org_mode = 0; + + if(ps_data->ps_enabled) + { + printk(KERN_INFO "%s: since PS is enabled, ges is disabled\n", __func__); + ps_data->re_enable_ges = enable; + return 0; + } + + if(enable == ps_data->ges_enabled) + return 0; + + if(enable) + { +#ifdef STK_QUALCOMM_POWER_CTRL + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; +#endif + if(ps_data->als_enabled) + { + printk(KERN_INFO "%s: force disable ALS\n", __func__); + stk3x1x_enable_als(ps_data, 0); + ps_data->re_enable_als = true; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, 0); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, 0); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + w_state_reg = STK_STATE_EN_WAIT_MASK | STK_STATE_EN_PS_MASK; + ret = stk3x1x_set_state(ps_data, w_state_reg); + if(ret < 0) + return ret; + ps_data->state_reg = w_state_reg; + + if(mode == 2) + { + ret = stk3x1x_get_gsctrl(ps_data); + if(ret < 0) + return ret; + gsctrl_reg = ret & 0xF3; +#ifdef STK_POLL_PS + gsctrl_reg |= 0x04; +#else + gsctrl_reg |= 0x0C; +#endif + ret = stk3x1x_set_gsctrl(ps_data, gsctrl_reg); + if(ret < 0) + return ret; +#ifdef STK_POLL_PS + hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL); +#else + enable_irq(ps_data->irq); +#endif + } + ps_data->ges_enabled = mode; + } + else + { + org_mode = ps_data->ges_enabled; + if(org_mode == 2) + { +#ifdef STK_POLL_PS + hrtimer_cancel(&ps_data->ps_timer); + cancel_work_sync(&ps_data->stk_ps_work); +#else + disable_irq(ps_data->irq); +#endif + } + + ret = stk3x1x_set_state(ps_data, 0); + if(ret < 0) + return ret; + ps_data->state_reg = 0; + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, ps_data->wait_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, ps_data->int_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + if(org_mode == 2) + { + ret = stk3x1x_get_gsctrl(ps_data); + if(ret < 0) + return ret; + gsctrl_reg = ret & (~0x0C); + ret = stk3x1x_set_gsctrl(ps_data, gsctrl_reg); + if(ret < 0) + return ret; + } + ps_data->ges_enabled = 0; + if(ps_data->re_enable_als) + { + printk(KERN_INFO "%s: re-enable ALS\n", __func__); + stk3x1x_enable_als(ps_data, 1); + ps_data->re_enable_als = false; + } +#ifdef STK_QUALCOMM_POWER_CTRL + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; +#endif + } + + return 0; +} +#endif /* #ifdef STK_GES */ + +static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable, uint8_t validate_reg) +{ + int32_t ret; + uint8_t w_state_reg; + uint8_t curr_ps_enable; + uint32_t reading; + int32_t near_far_state; + +#ifdef STK_QUALCOMM_POWER_CTRL + if (enable) { + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; + } +#endif + +#ifdef STK_CHK_REG + if(validate_reg) + { + ret = stk3x1x_validate_n_handle(ps_data->client); + if(ret < 0) + printk(KERN_ERR "stk3x1x_validate_n_handle fail: %d\n", ret); + } +#endif /* #ifdef STK_CHK_REG */ + +#ifdef STK_GES + if(ps_data->ges_enabled && enable) + { + printk(KERN_INFO "%s: force disable ges\n", __func__); + stk3x1x_enable_ges(ps_data, 0, 1); + ps_data->re_enable_ges = 1; + } +#endif + curr_ps_enable = ps_data->ps_enabled?1:0; + if(curr_ps_enable == enable) + return 0; + +#ifdef STK_TUNE0 + if (!(ps_data->psi_set) && !enable) + { + hrtimer_cancel(&ps_data->ps_tune0_timer); + cancel_work_sync(&ps_data->stk_ps_tune0_work); + } +#endif + if(ps_data->first_boot == true) + { + ps_data->first_boot = false; + } + + ret = stk3x1x_get_state(ps_data); + if(ret < 0) + return ret; + w_state_reg = ret; + + + w_state_reg &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK | STK_STATE_EN_AK_MASK); + if(enable) + { + w_state_reg |= STK_STATE_EN_PS_MASK; + if(!(ps_data->als_enabled)) + w_state_reg |= STK_STATE_EN_WAIT_MASK; + } + ret = stk3x1x_set_state(ps_data, w_state_reg); + if(ret < 0) + return ret; + ps_data->state_reg = w_state_reg; + + if(enable) + { +#ifdef STK_TUNE0 + #ifdef CALI_PS_EVERY_TIME + ps_data->psi_set = 0; + ps_data->psa = 0; + ps_data->psi = 0xFFFF; + #ifndef QUALCOMM_PLATFORM + ps_data->ps_thd_h = ps_data->ps_high_thd_boot; + ps_data->ps_thd_l = ps_data->ps_low_thd_boot; + #endif + hrtimer_start(&ps_data->ps_tune0_timer, ps_data->ps_tune0_delay, HRTIMER_MODE_REL); + #else + + if (!(ps_data->psi_set)) + hrtimer_start(&ps_data->ps_tune0_timer, ps_data->ps_tune0_delay, HRTIMER_MODE_REL); + #endif /* #ifdef CALI_PS_EVERY_TIME */ + stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); + stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); +#endif + printk(KERN_INFO "%s: HT=%d,LT=%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); +#ifdef STK_POLL_PS + hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL); + ps_data->ps_distance_last = -1; +#endif +#ifndef STK_POLL_PS + #ifndef STK_POLL_ALS + if(!(ps_data->als_enabled)) + #endif /* #ifndef STK_POLL_ALS */ + enable_irq(ps_data->irq); +#endif /* #ifndef STK_POLL_PS */ + ps_data->ps_enabled = true; +#ifdef STK_CHK_REG + if(!validate_reg) + { + ps_data->ps_distance_last = 1; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, 1); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + reading = stk3x1x_get_ps_reading(ps_data); + printk(KERN_INFO "%s: force report ps input event=1, ps code = %d\n",__func__, reading); + } + else +#endif /* #ifdef STK_CHK_REG */ + { + usleep_range(4000, 5000); + ret = stk3x1x_get_flag(ps_data); + if (ret < 0) + return ret; + near_far_state = ret & STK_FLG_NF_MASK; + ps_data->ps_distance_last = near_far_state; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + reading = stk3x1x_get_ps_reading(ps_data); + printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading); + } + } + else + { +#ifdef STK_POLL_PS + hrtimer_cancel(&ps_data->ps_timer); + cancel_work_sync(&ps_data->stk_ps_work); +#else +#ifndef STK_POLL_ALS + if(!(ps_data->als_enabled)) +#endif + disable_irq(ps_data->irq); +#endif + ps_data->ps_enabled = false; +#ifdef STK_GES + if(ps_data->re_enable_ges) + { + printk(KERN_INFO "%s: re-enable ges\n", __func__); + stk3x1x_enable_ges(ps_data, 1, 1); + ps_data->re_enable_ges = 0; + } +#endif +#ifdef STK_QUALCOMM_POWER_CTRL + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; +#endif + } + return ret; +} + +static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable) +{ + int32_t ret; + uint8_t w_state_reg; + uint8_t curr_als_enable = (ps_data->als_enabled)?1:0; + +#ifdef STK_GES + if(ps_data->ges_enabled) + { + printk(KERN_INFO "%s: since ges is enabled, ALS is disabled\n", __func__); + ps_data->re_enable_als = enable ? true : false; + return 0; + } +#endif /* #ifdef STK_GES */ + if(curr_als_enable == enable) + return 0; +#ifdef STK_QUALCOMM_POWER_CTRL + if (enable) { + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; + } +#endif +#ifndef STK_POLL_ALS + #ifdef STK_IRS + if(enable && !(ps_data->ps_enabled)) + { + ret = stk3x1x_get_ir_reading(ps_data, STK_IRS_IT_REDUCE ); + if(ret > 0) + ps_data->ir_code = ret; + } + #endif + + if (enable) + { + stk3x1x_set_als_thd_h(ps_data, 0x0000); + stk3x1x_set_als_thd_l(ps_data, 0xFFFF); + } +#endif + + ret = stk3x1x_get_state(ps_data); + if(ret < 0) + return ret; + + w_state_reg = (uint8_t)(ret & (~(STK_STATE_EN_ALS_MASK | STK_STATE_EN_WAIT_MASK))); + if(enable) + w_state_reg |= STK_STATE_EN_ALS_MASK; + else if (ps_data->ps_enabled) + w_state_reg |= STK_STATE_EN_WAIT_MASK; + + ret = stk3x1x_set_state(ps_data, w_state_reg); + if(ret < 0) + return ret; + ps_data->state_reg = w_state_reg; + + if (enable) + { + ps_data->als_enabled = true; +#ifdef STK_POLL_ALS + hrtimer_start(&ps_data->als_timer, ps_data->als_poll_delay, HRTIMER_MODE_REL); +#else +#ifndef STK_POLL_PS + if(!(ps_data->ps_enabled)) +#endif + enable_irq(ps_data->irq); +#endif +#ifdef STK_IRS + ps_data->als_data_index = 0; +#endif + } + else + { + ps_data->als_enabled = false; +#ifdef STK_POLL_ALS + hrtimer_cancel(&ps_data->als_timer); + cancel_work_sync(&ps_data->stk_als_work); +#else +#ifndef STK_POLL_PS + if(!(ps_data->ps_enabled)) +#endif + disable_irq(ps_data->irq); +#endif +#ifdef STK_QUALCOMM_POWER_CTRL + ret = stk3x1x_device_ctl(ps_data, enable); + if (ret) + return ret; +#endif + } + return ret; +} + +static int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data) +{ + int32_t als_data, ir_data = 0; +#ifdef STK_ALS_FIR + int index; + int firlen = atomic_read(&ps_data->firlength); +#endif + unsigned char value[2]; + int ret; + const int ir_enlarge = 1 << (STK_ALS_READ_IRS_IT_REDUCE - STK_IRS_IT_REDUCE); + + ret = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_ALS_REG, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + als_data = (value[0]<<8) | value[1]; + // printk("%s: raw als_data=%d\n", __func__, als_data); + if(ps_data->p_wv_r_bd_with_co & 0b010) + { + if(als_data < STK_ALS_THRESHOLD && ps_data->als_code_last > 10000) + { + ir_data = stk3x1x_get_ir_reading(ps_data, STK_ALS_READ_IRS_IT_REDUCE); +#ifdef STK_IRS + if(ir_data > 0) + ps_data->ir_code = ir_data * ir_enlarge; +#endif + // printk(KERN_INFO "%s: als_data=%d, als_code_last=%d,ir_data=%d\n", + // __func__, als_data, ps_data->als_code_last, ir_data); + if(ir_data > (STK_ALS_THRESHOLD*3)) + { + als_data = ps_data->als_code_last; + } + } +#ifdef STK_IRS + else + { + ps_data->ir_code = 0; + } +#endif + } + + ps_data->als_code_last = als_data; + +#ifdef STK_ALS_FIR + if(ps_data->fir.number < firlen) + { + ps_data->fir.raw[ps_data->fir.number] = als_data; + ps_data->fir.sum += als_data; + ps_data->fir.number++; + ps_data->fir.idx++; + } + else + { + index = ps_data->fir.idx % firlen; + ps_data->fir.sum -= ps_data->fir.raw[index]; + ps_data->fir.raw[index] = als_data; + ps_data->fir.sum += als_data; + ps_data->fir.idx++; + als_data = ps_data->fir.sum/firlen; + } +#endif + + return als_data; +} + + +#if (defined(STK_IRS) && defined(STK_POLL_ALS)) +static int stk_als_ir_skip_als(struct stk3x1x_data *ps_data) +{ + int ret; + unsigned char value[2]; + + if(ps_data->als_data_index < 60000) + ps_data->als_data_index++; + else + ps_data->als_data_index = 0; + + if( ps_data->als_data_index % 10 == 1) + { + ret = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_ALS_REG, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + return 1; + } + return 0; +} + +static void stk_als_ir_get_corr(struct stk3x1x_data *ps_data, int32_t als) +{ + int32_t als_comperator; + + if(ps_data->ir_code) + { + ps_data->als_correct_factor = 1000; + if(als < STK_IRC_MAX_ALS_CODE && als > STK_IRC_MIN_ALS_CODE && + ps_data->ir_code > STK_IRC_MIN_IR_CODE) + { + als_comperator = als * STK_IRC_ALS_NUMERA / STK_IRC_ALS_DENOMI; + if(ps_data->ir_code > als_comperator) + ps_data->als_correct_factor = STK_IRC_ALS_CORREC; + } +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: als=%d, ir=%d, als_correct_factor=%d", __func__, + als, ps_data->ir_code, ps_data->als_correct_factor); +#endif + ps_data->ir_code = 0; + } + return; +} + +static int stk_als_ir_run(struct stk3x1x_data *ps_data) +{ + int ret; + + if( ps_data->als_data_index % 10 == 0) + { + if(ps_data->ps_distance_last != 0 && ps_data->ir_code == 0) + { + ret = stk3x1x_get_ir_reading(ps_data, STK_IRS_IT_REDUCE); + if(ret > 0) + ps_data->ir_code = ret; + } + return ret; + } + return 0; +} +#endif /* #if (defined(STK_IRS) && defined(STK_POLL_ALS)) */ + + +static int32_t stk3x1x_set_irs_it_slp(struct stk3x1x_data *ps_data, uint16_t *slp_time, int32_t ials_it_reduce) +{ + uint8_t irs_alsctrl; + int32_t ret; + + irs_alsctrl = (ps_data->alsctrl_reg & 0x0F) - ials_it_reduce; + switch(irs_alsctrl) + { + case 2: + *slp_time = 1; + break; + case 3: + *slp_time = 2; + break; + case 4: + *slp_time = 3; + break; + case 5: + *slp_time = 6; + break; + case 6: + *slp_time = 12; + break; + case 7: + *slp_time = 24; + break; + case 8: + *slp_time = 48; + break; + case 9: + *slp_time = 96; + break; + case 10: + *slp_time = 192; + break; + default: + printk(KERN_ERR "%s: unknown ALS IT=0x%x\n", __func__, irs_alsctrl); + ret = -EINVAL; + return ret; + } + irs_alsctrl |= (ps_data->alsctrl_reg & 0xF0); + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, irs_alsctrl); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + return 0; +} + +static int32_t stk3x1x_get_ir_reading(struct stk3x1x_data *ps_data, int32_t als_it_reduce) +{ + int32_t word_data, ret; + uint8_t w_reg, retry = 0; + uint16_t irs_slp_time = 100; + unsigned char value[2]; + + ret = stk3x1x_set_irs_it_slp(ps_data, &irs_slp_time, als_it_reduce); + if(ret < 0) + goto irs_err_i2c_rw; + + ret = stk3x1x_get_state(ps_data); + if(ret < 0) + goto irs_err_i2c_rw; + + w_reg = ret | STK_STATE_EN_IRS_MASK; + ret = stk3x1x_set_state(ps_data, w_reg); + if(ret < 0) + goto irs_err_i2c_rw; + msleep(irs_slp_time); + + do + { + usleep_range(3000, 4000); + ret = stk3x1x_get_flag(ps_data); + if (ret < 0) + goto irs_err_i2c_rw; + retry++; + }while(retry < 10 && ((ret&STK_FLG_IR_RDY_MASK) == 0)); + + if(retry == 10) + { + printk(KERN_ERR "%s: ir data is not ready for a long time\n", __func__); + ret = -EINVAL; + goto irs_err_i2c_rw; + } + + ret = stk3x1x_set_flag(ps_data, ret, STK_FLG_IR_RDY_MASK); + if (ret < 0) + goto irs_err_i2c_rw; + + ret = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_IR_REG, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + goto irs_err_i2c_rw; + } + word_data = ((value[0]<<8) | value[1]); + //printk(KERN_INFO "%s: ir=%d\n", __func__, word_data); + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, ps_data->alsctrl_reg ); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + goto irs_err_i2c_rw; + } + + return word_data; + +irs_err_i2c_rw: + return ret; +} + +#ifdef STK_CHK_REG +static int stk3x1x_chk_reg_valid(struct stk3x1x_data *ps_data) +{ + unsigned char value[9]; + int err; + /* + uint8_t cnt; + + for(cnt=0;cnt<9;cnt++) + { + value[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, (cnt+1)); + if(value[cnt] < 0) + { + printk(KERN_ERR "%s fail, ret=%d", __func__, value[cnt]); + return value[cnt]; + } + } + */ + err = stk3x1x_i2c_read_data(ps_data->client, STK_PSCTRL_REG, 9, &value[0]); + if(err < 0) + { + printk(KERN_ERR "%s: fail, ret=%d\n", __func__, err); + return err; + } + + if(value[0] != ps_data->psctrl_reg) + { + printk(KERN_ERR "%s: invalid reg 0x01=0x%2x\n", __func__, value[0]); + return 0xFF; + } +#ifdef STK_IRS + if((value[1] != ps_data->alsctrl_reg) && (value[1] != (ps_data->alsctrl_reg - STK_IRS_IT_REDUCE)) + && (value[1] != (ps_data->alsctrl_reg - STK_ALS_READ_IRS_IT_REDUCE))) +#else + if((value[1] != ps_data->alsctrl_reg) && (value[1] != (ps_data->alsctrl_reg - STK_ALS_READ_IRS_IT_REDUCE))) +#endif + { + printk(KERN_ERR "%s: invalid reg 0x02=0x%2x\n", __func__, value[1]); + return 0xFF; + } + if(value[2] != ps_data->ledctrl_reg) + { + printk(KERN_ERR "%s: invalid reg 0x03=0x%2x\n", __func__, value[2]); + return 0xFF; + } + if(value[3] != ps_data->int_reg) + { + printk(KERN_ERR "%s: invalid reg 0x04=0x%2x\n", __func__, value[3]); + return 0xFF; + } + if(value[4] != ps_data->wait_reg) + { + printk(KERN_ERR "%s: invalid reg 0x05=0x%2x\n", __func__, value[4]); + return 0xFF; + } + if(value[5] != ((ps_data->ps_thd_h & 0xFF00) >> 8)) + { + printk(KERN_ERR "%s: invalid reg 0x06=0x%2x\n", __func__, value[5]); + return 0xFF; + } + if(value[6] != (ps_data->ps_thd_h & 0x00FF)) + { + printk(KERN_ERR "%s: invalid reg 0x07=0x%2x\n", __func__, value[6]); + return 0xFF; + } + if(value[7] != ((ps_data->ps_thd_l & 0xFF00) >> 8)) + { + printk(KERN_ERR "%s: invalid reg 0x08=0x%2x\n", __func__, value[7]); + return 0xFF; + } + if(value[8] != (ps_data->ps_thd_l & 0x00FF)) + { + printk(KERN_ERR "%s: invalid reg 0x09=0x%2x\n", __func__, value[8]); + return 0xFF; + } + + return 0; +} + +static int stk3x1x_validate_n_handle(struct i2c_client *client) +{ + struct stk3x1x_data *ps_data = i2c_get_clientdata(client); + int err; + + err = stk3x1x_chk_reg_valid(ps_data); + if(err < 0) + { + printk(KERN_ERR "stk3x1x_chk_reg_valid fail: %d\n", err); + return err; + } + + if(err == 0xFF) + { + printk(KERN_ERR "%s: Re-init chip\n", __func__); + err = stk3x1x_software_reset(ps_data); + if(err < 0) + return err; + err = stk3x1x_init_all_reg(ps_data); + if(err < 0) + return err; + + //ps_data->psa = 0; + //ps_data->psi = 0xFFFF; + stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); + stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); +#ifdef STK_ALS_FIR + memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); +#endif + return 0xFF; + } + return 0; +} +#endif /* #ifdef STK_CHK_REG */ + +static ssize_t stk_als_code_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t reading; +#ifdef STK_POLL_ALS + reading = ps_data->als_code_last; +#else + unsigned char value[2]; + int ret; + ret = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_ALS_REG, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + reading = (value[0]<<8) | value[1]; +#endif + return scnprintf(buf, PAGE_SIZE, "%d\n", reading); +} + + +static ssize_t stk_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t ret; + + ret = stk3x1x_get_state(ps_data); + if(ret < 0) + return ret; + ret = (ret & STK_STATE_EN_ALS_MASK)?1:0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t stk_als_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + uint8_t en; + if (sysfs_streq(buf, "1")) + en = 1; + else if (sysfs_streq(buf, "0")) + en = 0; + else + { + printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf); + return -EINVAL; + } + printk(KERN_INFO "%s: Enable ALS : %d\n", __func__, en); + mutex_lock(&ps_data->io_lock); + stk3x1x_enable_als(ps_data, en); + mutex_unlock(&ps_data->io_lock); + return size; +} + +static ssize_t stk_als_lux_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t als_reading; + uint32_t als_lux; + als_reading = stk3x1x_get_als_reading(ps_data); + als_lux = stk_alscode2lux(ps_data, als_reading); + return scnprintf(buf, PAGE_SIZE, "%d lux\n", als_lux); +} + +static ssize_t stk_als_lux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + ret = kstrtoul(buf, 16, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->als_lux_last = value; + input_report_abs(ps_data->als_input_dev, ABS_MISC, value); + input_sync(ps_data->als_input_dev); + printk(KERN_INFO "%s: als input event %ld lux\n",__func__, value); + + return size; +} + + +static ssize_t stk_als_transmittance_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t transmittance; + transmittance = ps_data->als_transmittance; + return scnprintf(buf, PAGE_SIZE, "%d\n", transmittance); +} + + +static ssize_t stk_als_transmittance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + ret = kstrtoul(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->als_transmittance = value; + return size; +} + +static ssize_t stk_als_delay_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int64_t delay; + mutex_lock(&ps_data->io_lock); + delay = ktime_to_ns(ps_data->als_poll_delay); + mutex_unlock(&ps_data->io_lock); + return scnprintf(buf, PAGE_SIZE, "%lld\n", delay); +} + + +static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + uint64_t value = 0; + int ret; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + ret = kstrtoull(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n", __func__, ret); + return ret; + } +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: set als poll delay=%lld\n", __func__, value); +#endif + if(value < MIN_ALS_POLL_DELAY_NS) + { + printk(KERN_ERR "%s: delay is too small\n", __func__); + value = MIN_ALS_POLL_DELAY_NS; + } + mutex_lock(&ps_data->io_lock); + if(value != ktime_to_ns(ps_data->als_poll_delay)) + ps_data->als_poll_delay = ns_to_ktime(value); +#ifdef STK_ALS_FIR + ps_data->fir.number = 0; + ps_data->fir.idx = 0; + ps_data->fir.sum = 0; +#endif + mutex_unlock(&ps_data->io_lock); + return size; +} + +static ssize_t stk_als_ir_code_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t reading; + reading = stk3x1x_get_ir_reading(ps_data, STK_IRS_IT_REDUCE); + return scnprintf(buf, PAGE_SIZE, "%d\n", reading); +} + +#ifdef STK_ALS_FIR +static ssize_t stk_als_firlen_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int len = atomic_read(&ps_data->firlength); + + printk(KERN_INFO "%s: len = %2d, idx = %2d\n", __func__, len, ps_data->fir.idx); + printk(KERN_INFO "%s: sum = %5d, ave = %5d\n", __func__, ps_data->fir.sum, ps_data->fir.sum/len); + + return scnprintf(buf, PAGE_SIZE, "%d\n", len); +} + + +static ssize_t stk_als_firlen_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + uint64_t value = 0; + int ret; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + ret = kstrtoull(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n", __func__, ret); + return ret; + } + + if(value > MAX_FIR_LEN) + { + printk(KERN_ERR "%s: firlen exceed maximum filter length\n", __func__); + } + else if (value < 1) + { + atomic_set(&ps_data->firlength, 1); + memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); + } + else + { + atomic_set(&ps_data->firlength, value); + memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); + } + return size; +} +#endif /* #ifdef STK_ALS_FIR */ + +#ifdef STK_GES +static ssize_t stk_ges_code_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int ret; + unsigned int gest0 = 0, gest1 = 0, gest2 = 0; + + if(!ps_data->ges_enabled) + return 0; + + ret = stk3x1x_get_ges_reading(ps_data, &gest0, &gest1, &gest2); + if(ret < 0) + return ret; + else if(ret == 0xFFFF) + atomic_set(&ps_data->gesture2, 0); + + return scnprintf(buf, PAGE_SIZE, "%5d,%5d,%5d\n", gest0, gest1, atomic_read(&ps_data->gesture2)); +} + +static ssize_t stk_ges_code_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + uint8_t ges; + unsigned long value = 0; + int ret; + + ret = kstrtoul(buf, 16, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=%d\n", __func__, ret); + return ret; + } + + switch(value) + { + case 3: + //printk(KERN_INFO "%s: ges input event, not detected\n",__func__); + case 0: + return size; + case 1: + ges = KEY_PAGEUP; + atomic_set(&ps_data->gesture2, 0); + printk(KERN_INFO "%s: ges input event >>>\n",__func__); + break; + case 2: + ges = KEY_PAGEDOWN; + atomic_set(&ps_data->gesture2, 0); + printk(KERN_INFO "%s: ges input event <<<\n",__func__); + break; + case 32: + ges = KEY_VOLUMEDOWN; + printk(KERN_INFO "%s: ges input event near\n",__func__); + break; + case 48: + ges = KEY_VOLUMEUP; + printk(KERN_INFO "%s: ges input event far\n",__func__); + break; + default: + printk(KERN_ERR "%s, invalid value %d\n", __func__, (int)value); + return -EINVAL; + } + + input_report_key(ps_data->ges_input_dev, ges, 1); + input_report_key(ps_data->ges_input_dev, ges, 0); + input_sync(ps_data->ges_input_dev); + return size; +} + +static ssize_t stk_ges_poll_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int len = 0, ii = 0, jj = 0; + + while(stk_ges_op[ii].ops[0] != 0) + { + len += scnprintf(buf + len, PAGE_SIZE - len, "%x ", ii); + for(jj=0;jj<4;jj++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%x ", stk_ges_op[ii].ops[jj]); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + ii++; + } + return len; +} + + +static ssize_t stk_ges_poll_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int32_t ret, i = 0, index = 0; + char *token; + unsigned long value = 0; + + while(buf != '\0') + { + token = strsep((char **)&buf, " "); + if((ret = kstrtoul(token, 16, &value)) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + + if(i == 0) + { + if(value >= 10) + { + memset(stk_ges_op, 0, sizeof(stk_ges_op)); + break; + } + else + index = value; + } + else + { + stk_ges_op[index].ops[i-1] = value; + } + i++; + if(i == 5) + break; + } + if(i != 5) + { + printk(KERN_ERR "%s: invalid length(%d)\n", __func__, i); + memset(&(stk_ges_op[index]), 0, sizeof(union stk_ges_operation)); + } + return size; +} + +static ssize_t stk_ges_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + ret = kstrtoul(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=%d\n", __func__, ret); + return ret; + } + printk(KERN_INFO "%s: Enable GES : %d\n", __func__, (int)value); + + switch(value) + { + case 0: + mutex_lock(&ps_data->io_lock); + if(ps_data->ges_enabled == 1) + stk3x1x_enable_ges(ps_data, 0, 1); + else + stk3x1x_enable_ges(ps_data, 0, 2); + mutex_unlock(&ps_data->io_lock); + break; + case 1: + mutex_lock(&ps_data->io_lock); + stk3x1x_enable_ges(ps_data, 1, 1); + mutex_unlock(&ps_data->io_lock); + break; + case 2: + mutex_lock(&ps_data->io_lock); + stk3x1x_enable_ges(ps_data, 1, 2); + mutex_unlock(&ps_data->io_lock); + break; + default: + printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf); + return -EINVAL; + break; + } + + return size; +} + +static ssize_t stk_ges_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_data->ges_enabled); +} + +#endif /* #ifdef STK_GES */ + +static ssize_t stk_ps_code_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + uint32_t reading; + reading = stk3x1x_get_ps_reading(ps_data); + return scnprintf(buf, PAGE_SIZE, "%d\n", reading); +} + +static ssize_t stk_ps_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ret; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + + ret = stk3x1x_get_state(ps_data); + if(ret < 0) + return ret; + ret = (ret & STK_STATE_EN_PS_MASK)?1:0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t stk_ps_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + uint8_t en; + if (sysfs_streq(buf, "1")) + en = 1; + else if (sysfs_streq(buf, "0")) + en = 0; + else + { + printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf); + return -EINVAL; + } + printk(KERN_INFO "%s: Enable PS : %d\n", __func__, en); + mutex_lock(&ps_data->io_lock); + stk3x1x_enable_ps(ps_data, en, 1); + mutex_unlock(&ps_data->io_lock); + return size; +} + +static ssize_t stk_ps_enable_aso_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ret; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG); + ret = (ret & STK_STATE_EN_ASO_MASK)?1:0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t stk_ps_enable_aso_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + uint8_t en; + int32_t ret; + uint8_t w_state_reg; + + if (sysfs_streq(buf, "1")) + en = 1; + else if (sysfs_streq(buf, "0")) + en = 0; + else + { + printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf); + return -EINVAL; + } + printk(KERN_INFO "%s: Enable PS ASO : %d\n", __func__, en); + + ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_ASO_MASK)); + if(en) + w_state_reg |= STK_STATE_EN_ASO_MASK; + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + return size; +} + + +static ssize_t stk_ps_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t word_data; + unsigned char value[2]; + int ret; + + ret = stk3x1x_i2c_read_data(ps_data->client, STK_DATA1_OFFSET_REG, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + word_data = (value[0]<<8) | value[1]; + + return scnprintf(buf, PAGE_SIZE, "%d\n", word_data); +} + +static ssize_t stk_ps_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long offset = 0; + int ret; + unsigned char val[2]; + + ret = kstrtoul(buf, 10, &offset); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + if(offset > 65535) + { + printk(KERN_ERR "%s: invalid value, offset=%ld\n", __func__, offset); + return -EINVAL; + } + + val[0] = (offset & 0xFF00) >> 8; + val[1] = offset & 0x00FF; + ret = stk3x1x_i2c_write_data(ps_data->client, STK_DATA1_OFFSET_REG, 2, val); + if(ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + return size; +} + + +static ssize_t stk_ps_distance_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t dist=1, ret; + + ret = stk3x1x_get_flag(ps_data); + if(ret < 0) + return ret; + dist = (ret & STK_FLG_NF_MASK)?1:0; + + ps_data->ps_distance_last = dist; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, dist); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + printk(KERN_INFO "%s: ps input event %d cm\n",__func__, dist); + return scnprintf(buf, PAGE_SIZE, "%d\n", dist); +} + + +static ssize_t stk_ps_distance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + ret = kstrtoul(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->ps_distance_last = value; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, value); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + printk(KERN_INFO "%s: ps input event %ld cm\n",__func__, value); + return size; +} + + +static ssize_t stk_ps_code_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ps_thd_l1_reg, ps_thd_l2_reg; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + ps_thd_l1_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_PS_REG); + if(ps_thd_l1_reg < 0) + { + printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l1_reg); + return -EINVAL; + } + ps_thd_l2_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_THDL2_PS_REG); + if(ps_thd_l2_reg < 0) + { + printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l2_reg); + return -EINVAL; + } + ps_thd_l1_reg = ps_thd_l1_reg<<8 | ps_thd_l2_reg; + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_l1_reg); +} + + +static ssize_t stk_ps_code_thd_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + ret = kstrtoul(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + stk3x1x_set_ps_thd_l(ps_data, value); + return size; +} + +static ssize_t stk_ps_code_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ps_thd_h1_reg, ps_thd_h2_reg; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + ps_thd_h1_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_PS_REG); + if(ps_thd_h1_reg < 0) + { + printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h1_reg); + return -EINVAL; + } + ps_thd_h2_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,STK_THDH2_PS_REG); + if(ps_thd_h2_reg < 0) + { + printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h2_reg); + return -EINVAL; + } + ps_thd_h1_reg = ps_thd_h1_reg<<8 | ps_thd_h2_reg; + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_h1_reg); +} + + +static ssize_t stk_ps_code_thd_h_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + ret = kstrtoul(buf, 10, &value); + if(ret < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + stk3x1x_set_ps_thd_h(ps_data, value); + return size; +} + + +static ssize_t stk_all_reg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ps_reg[0x22]; + uint8_t cnt; + int len = 0; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + + for(cnt=0;cnt<0x20;cnt++) + { + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, (cnt)); + if(ps_reg[cnt] < 0) + { + printk(KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + else + { + printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]); + len += scnprintf(buf+len, PAGE_SIZE-len, "[%2X]%2X,", cnt, ps_reg[cnt]); + } + } + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG); + if(ps_reg[cnt] < 0) + { + printk( KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]); + cnt++; + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG); + if(ps_reg[cnt] < 0) + { + printk( KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]); + len += scnprintf(buf+len, PAGE_SIZE-len, "[%2X]%2X,[%2X]%2X\n", cnt-1, ps_reg[cnt-1], cnt, ps_reg[cnt]); + return len; +/* + return scnprintf(buf, PAGE_SIZE, "[0]%2X [1]%2X [2]%2X [3]%2X [4]%2X [5]%2X [6/7 HTHD]%2X,%2X [8/9 LTHD]%2X, %2X [A]%2X [B]%2X [C]%2X [D]%2X [E/F Aoff]%2X,%2X,[10]%2X [11/12 PS]%2X,%2X [13]%2X [14]%2X [15/16 Foff]%2X,%2X [17]%2X [18]%2X [3E]%2X [3F]%2X\n", + ps_reg[0], ps_reg[1], ps_reg[2], ps_reg[3], ps_reg[4], ps_reg[5], ps_reg[6], ps_reg[7], ps_reg[8], + ps_reg[9], ps_reg[10], ps_reg[11], ps_reg[12], ps_reg[13], ps_reg[14], ps_reg[15], ps_reg[16], ps_reg[17], + ps_reg[18], ps_reg[19], ps_reg[20], ps_reg[21], ps_reg[22], ps_reg[23], ps_reg[24], ps_reg[25], ps_reg[26]); + */ +} + +static ssize_t stk_status_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int32_t ps_reg[27]; + uint8_t cnt; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + for(cnt=0;cnt<25;cnt++) + { + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, (cnt)); + if(ps_reg[cnt] < 0) + { + printk(KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + else + { + printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]); + } + } + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG); + if(ps_reg[cnt] < 0) + { + printk( KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]); + cnt++; + ps_reg[cnt] = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG); + if(ps_reg[cnt] < 0) + { + printk( KERN_ERR "%s fail, ret=%d", __func__, ps_reg[cnt]); + return -EINVAL; + } + printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]); + + return scnprintf(buf, PAGE_SIZE, "[PS=%2X] [ALS=%2X] [WAIT=0x%4Xms] [EN_ASO=%2X] [EN_AK=%2X] [NEAR/FAR=%2X] [FLAG_OUI=%2X] [FLAG_PSINT=%2X] [FLAG_ALSINT=%2X]\n", + ps_reg[0]&0x01,(ps_reg[0]&0x02)>>1,((ps_reg[0]&0x04)>>2)*ps_reg[5]*6,(ps_reg[0]&0x20)>>5, + (ps_reg[0]&0x40)>>6,ps_reg[16]&0x01,(ps_reg[16]&0x04)>>2,(ps_reg[16]&0x10)>>4,(ps_reg[16]&0x20)>>5); +} + +static ssize_t stk_recv_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "0x%04X\n", atomic_read(&ps_data->recv_reg)); +} + + +static ssize_t stk_recv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned long value = 0; + int ret; + int32_t recv_data; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + + if((ret = kstrtoul(buf, 16, &value)) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + recv_data = stk3x1x_i2c_smbus_read_byte_data(ps_data->client,value); +// printk("%s: reg 0x%x=0x%x\n", __func__, (int)value, recv_data); + atomic_set(&ps_data->recv_reg, recv_data); + return size; +} + + +static ssize_t stk_send_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return 0; +} + + +static ssize_t stk_send_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int addr, cmd; + int32_t ret, i; + char *token[10]; + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + + for (i = 0; i < 2; i++) + token[i] = strsep((char **)&buf, " "); + if((ret = kstrtoul(token[0], 16, (unsigned long *)&(addr))) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + if((ret = kstrtoul(token[1], 16, (unsigned long *)&(cmd))) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd); + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, (unsigned char)addr, (unsigned char)cmd); + if (0 != ret) + { + printk(KERN_ERR "%s: stk3x1x_i2c_smbus_write_byte_data fail\n", __func__); + return ret; + } + + return size; +} + +#ifdef STK_TUNE0 + +static ssize_t stk_ps_cali_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + int32_t word_data; + unsigned char value[2]; + int ret; + + ret = stk3x1x_i2c_read_data(ps_data->client, 0x20, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + word_data = (value[0]<<8) | value[1]; + + ret = stk3x1x_i2c_read_data(ps_data->client, 0x22, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + word_data += ((value[0]<<8) | value[1]); + + printk("%s: psi_set=%d, psa=%d,psi=%d, word_data=%d\n", __func__, + ps_data->psi_set, ps_data->psa, ps_data->psi, word_data); +#ifdef CALI_PS_EVERY_TIME + printk("%s: boot HT=%d, LT=%d\n", __func__, ps_data->ps_high_thd_boot, ps_data->ps_low_thd_boot); +#endif + return 0; +} + +static ssize_t stk_ps_maxdiff_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + if((ret = kstrtoul(buf, 10, &value)) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->stk_max_min_diff = (int) value; + return size; +} + + +static ssize_t stk_ps_maxdiff_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_data->stk_max_min_diff); +} + +static ssize_t stk_ps_ltnct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + if((ret = kstrtoul(buf, 10, &value)) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->stk_lt_n_ct = (int) value; + return size; +} + +static ssize_t stk_ps_ltnct_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_data->stk_lt_n_ct); +} + +static ssize_t stk_ps_htnct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + unsigned long value = 0; + int ret; + + if((ret = kstrtoul(buf, 10, &value)) < 0) + { + printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); + return ret; + } + ps_data->stk_ht_n_ct = (int) value; + return size; +} + +static ssize_t stk_ps_htnct_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", ps_data->stk_ht_n_ct); +} +#endif /* #ifdef STK_TUNE0 */ + +static struct device_attribute als_enable_attribute = __ATTR(enable,0666,stk_als_enable_show,stk_als_enable_store); +static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store); +static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL); +static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store); +static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store); +static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL); +#ifdef STK_ALS_FIR +static struct device_attribute als_firlen_attribute = __ATTR(firlen,0664,stk_als_firlen_show,stk_als_firlen_store); +#endif + +static struct attribute *stk_als_attrs [] = +{ + &als_enable_attribute.attr, + &als_lux_attribute.attr, + &als_code_attribute.attr, + &als_transmittance_attribute.attr, + &als_poll_delay_attribute.attr, + &als_ir_code_attribute.attr, +#ifdef STK_ALS_FIR + &als_firlen_attribute.attr, +#endif + NULL +}; + +static struct attribute_group stk_als_attribute_group = { +#ifndef QUALCOMM_PLATFORM + .name = "driver", +#endif + .attrs = stk_als_attrs, +}; + +#ifdef STK_GES +static struct device_attribute ges_enable_attribute = __ATTR(enable,0666,stk_ges_enable_show,stk_ges_enable_store); +static struct device_attribute ges_code_attribute = __ATTR(code, 0664, stk_ges_code_show, stk_ges_code_store); +static struct device_attribute ges_poll_attribute = __ATTR(poll, 0664, stk_ges_poll_show, stk_ges_poll_store); +static struct device_attribute ges_recv_attribute = __ATTR(recv,0664,stk_recv_show,stk_recv_store); +static struct device_attribute ges_send_attribute = __ATTR(send,0664,stk_send_show, stk_send_store); + +static struct attribute *stk_ges_attrs [] = +{ + &ges_enable_attribute.attr, + &ges_code_attribute.attr, + &ges_poll_attribute.attr, + &ges_recv_attribute.attr, + &ges_send_attribute.attr, + NULL +}; + +static struct attribute_group stk_ges_attribute_group = +{ + .name = "driver", + .attrs = stk_ges_attrs, +}; +#endif /* #ifdef STK_GES */ + +static struct device_attribute ps_enable_attribute = __ATTR(enable,0666,stk_ps_enable_show,stk_ps_enable_store); +static struct device_attribute ps_enable_aso_attribute = __ATTR(enableaso,0664,stk_ps_enable_aso_show,stk_ps_enable_aso_store); +static struct device_attribute ps_distance_attribute = __ATTR(distance,0664,stk_ps_distance_show, stk_ps_distance_store); +static struct device_attribute ps_offset_attribute = __ATTR(offset,0664,stk_ps_offset_show, stk_ps_offset_store); +static struct device_attribute ps_code_attribute = __ATTR(code, 0444, stk_ps_code_show, NULL); +static struct device_attribute ps_code_thd_l_attribute = __ATTR(codethdl,0664,stk_ps_code_thd_l_show,stk_ps_code_thd_l_store); +static struct device_attribute ps_code_thd_h_attribute = __ATTR(codethdh,0664,stk_ps_code_thd_h_show,stk_ps_code_thd_h_store); +static struct device_attribute ps_recv_attribute = __ATTR(recv,0664,stk_recv_show,stk_recv_store); +static struct device_attribute ps_send_attribute = __ATTR(send,0664,stk_send_show, stk_send_store); +static struct device_attribute all_reg_attribute = __ATTR(allreg, 0444, stk_all_reg_show, NULL); +static struct device_attribute status_attribute = __ATTR(status, 0444, stk_status_show, NULL); +#ifdef STK_TUNE0 +static struct device_attribute ps_cali_attribute = __ATTR(cali,0444,stk_ps_cali_show, NULL); +static struct device_attribute ps_maxdiff_attribute = __ATTR(maxdiff,0664,stk_ps_maxdiff_show, stk_ps_maxdiff_store); +static struct device_attribute ps_ltnct_attribute = __ATTR(ltnct,0664,stk_ps_ltnct_show, stk_ps_ltnct_store); +static struct device_attribute ps_htnct_attribute = __ATTR(htnct,0664,stk_ps_htnct_show, stk_ps_htnct_store); +#endif + +static struct attribute *stk_ps_attrs [] = +{ + &ps_enable_attribute.attr, + &ps_enable_aso_attribute.attr, + &ps_distance_attribute.attr, + &ps_offset_attribute.attr, + &ps_code_attribute.attr, + &ps_code_thd_l_attribute.attr, + &ps_code_thd_h_attribute.attr, + &ps_recv_attribute.attr, + &ps_send_attribute.attr, + &all_reg_attribute.attr, + &status_attribute.attr, +#ifdef STK_TUNE0 + &ps_cali_attribute.attr, + &ps_maxdiff_attribute.attr, + &ps_ltnct_attribute.attr, + &ps_htnct_attribute.attr, +#endif + NULL +}; + +static struct attribute_group stk_ps_attribute_group = { +#ifndef QUALCOMM_PLATFORM + .name = "driver", +#endif + .attrs = stk_ps_attrs, +}; + +static int stk_ps_val(struct stk3x1x_data *ps_data) +{ + int mode; + int32_t word_data, lii; + unsigned char value[4]; + int ret; + + ret = stk3x1x_i2c_read_data(ps_data->client, 0x20, 4, value); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + word_data = (value[0]<<8) | value[1]; + word_data += ((value[2]<<8) | value[3]); + + mode = (ps_data->psctrl_reg) & 0x3F; + if(mode == 0x30) + lii = 100; + else if (mode == 0x31) + lii = 200; + else if (mode == 0x32) + lii = 400; + else if (mode == 0x33) + lii = 800; + else + { + printk(KERN_ERR "%s: unsupported PS_IT(0x%x)\n", __func__, mode); + return -1; + } + + if(word_data > lii) + { + printk(KERN_INFO "%s: word_data=%d, lii=%d\n", __func__, word_data, lii); + return 0xFFFF; + } + return 0; +} + +#ifdef STK_TUNE0 + +static int stk_ps_tune_zero_final(struct stk3x1x_data *ps_data) +{ + int ret; + + ps_data->tune_zero_init_proc = false; + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, ps_data->int_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, 0); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + if(ps_data->data_count == -1) + { + printk(KERN_INFO "%s: exceed limit\n", __func__); + hrtimer_cancel(&ps_data->ps_tune0_timer); + return 0; + } + + ps_data->psa = ps_data->ps_stat_data[0]; + ps_data->psi = ps_data->ps_stat_data[2]; + +#ifdef CALI_PS_EVERY_TIME + ps_data->ps_high_thd_boot = ps_data->ps_stat_data[1] + ps_data->stk_ht_n_ct*3; + ps_data->ps_low_thd_boot = ps_data->ps_stat_data[1] + ps_data->stk_lt_n_ct*3; + ps_data->ps_thd_h = ps_data->ps_high_thd_boot ; + ps_data->ps_thd_l = ps_data->ps_low_thd_boot ; +#else + ps_data->ps_thd_h = ps_data->ps_stat_data[1] + ps_data->stk_ht_n_ct; + ps_data->ps_thd_l = ps_data->ps_stat_data[1] + ps_data->stk_lt_n_ct; +#endif + stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); + stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); + printk(KERN_INFO "%s: set HT=%d,LT=%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); + hrtimer_cancel(&ps_data->ps_tune0_timer); + return 0; +} + +static int32_t stk_tune_zero_get_ps_data(struct stk3x1x_data *ps_data) +{ + uint32_t ps_adc; + int ret; + + ret = stk_ps_val(ps_data); + if(ret == 0xFFFF) + { + ps_data->data_count = -1; + stk_ps_tune_zero_final(ps_data); + return 0; + } + + ps_adc = stk3x1x_get_ps_reading(ps_data); + printk(KERN_INFO "%s: ps_adc #%d=%d\n", __func__, ps_data->data_count, ps_adc); + if(ps_adc < 0) + return ps_adc; + + ps_data->ps_stat_data[1] += ps_adc; + if(ps_adc > ps_data->ps_stat_data[0]) + ps_data->ps_stat_data[0] = ps_adc; + if(ps_adc < ps_data->ps_stat_data[2]) + ps_data->ps_stat_data[2] = ps_adc; + ps_data->data_count++; + + if(ps_data->data_count == 5) + { + ps_data->ps_stat_data[1] /= ps_data->data_count; + stk_ps_tune_zero_final(ps_data); + } + + return 0; +} +static int stk_ps_tune_zero_init(struct stk3x1x_data *ps_data) +{ + int32_t ret = 0; + uint8_t w_state_reg; + + ps_data->psi_set = 0; + ps_data->ps_stat_data[0] = 0; + ps_data->ps_stat_data[2] = 9999; + ps_data->ps_stat_data[1] = 0; + ps_data->data_count = 0; + + ps_data->tune_zero_init_proc = true; + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, 0); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + + w_state_reg = (STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK); + ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg); + if (ret < 0) + { + printk(KERN_ERR "%s: write i2c error\n", __func__); + return ret; + } + hrtimer_start(&ps_data->ps_tune0_timer, ps_data->ps_tune0_delay, HRTIMER_MODE_REL); + + return 0; +} +static int stk_ps_tune_zero_func_fae(struct stk3x1x_data *ps_data) +{ + int32_t word_data; + int ret, diff; + unsigned char value[2]; + +#ifdef CALI_PS_EVERY_TIME + if(!(ps_data->ps_enabled)) +#else + if(ps_data->psi_set || !(ps_data->ps_enabled)) +#endif + { + return 0; + } + + ret = stk3x1x_get_flag(ps_data); + if(ret < 0) + return ret; + if(!(ret&STK_FLG_PSDR_MASK)) + { + //printk(KERN_INFO "%s: ps data is not ready yet\n", __func__); + return 0; + } + + ret = stk_ps_val(ps_data); + if(ret == 0) + { + ret = stk3x1x_i2c_read_data(ps_data->client, 0x11, 2, &value[0]); + if(ret < 0) + { + printk(KERN_ERR "%s fail, ret=0x%x", __func__, ret); + return ret; + } + word_data = (value[0]<<8) | value[1]; + //printk(KERN_INFO "%s: word_data=%d\n", __func__, word_data); + + if(word_data == 0) + { + //printk(KERN_ERR "%s: incorrect word data (0)\n", __func__); + return 0xFFFF; + } + + if(word_data > ps_data->psa) + { + ps_data->psa = word_data; + printk(KERN_INFO "%s: update psa: psa=%d,psi=%d\n", __func__, ps_data->psa, ps_data->psi); + } + if(word_data < ps_data->psi) + { + ps_data->psi = word_data; + printk(KERN_INFO "%s: update psi: psa=%d,psi=%d\n", __func__, ps_data->psa, ps_data->psi); + } + } + diff = ps_data->psa - ps_data->psi; + if(diff > ps_data->stk_max_min_diff) + { + ps_data->psi_set = ps_data->psi; + ps_data->ps_thd_h = ps_data->psi + ps_data->stk_ht_n_ct; + ps_data->ps_thd_l = ps_data->psi + ps_data->stk_lt_n_ct; + + +#ifdef CALI_PS_EVERY_TIME + if(ps_data->ps_thd_h > ps_data->ps_high_thd_boot) + { + ps_data->ps_high_thd_boot = ps_data->ps_thd_h; + ps_data->ps_low_thd_boot = ps_data->ps_thd_l; + printk(KERN_INFO "%s: update boot HT=%d, LT=%d\n", __func__, ps_data->ps_high_thd_boot, ps_data->ps_low_thd_boot); + } +#endif + + stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); + stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: FAE tune0 psa-psi(%d) > STK_DIFF found\n", __func__, diff); +#endif + hrtimer_cancel(&ps_data->ps_tune0_timer); + } + + return 0; +} + +static void stk_ps_tune0_work_func(struct work_struct *work) +{ + struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_ps_tune0_work); + if(ps_data->tune_zero_init_proc) + stk_tune_zero_get_ps_data(ps_data); + else + stk_ps_tune_zero_func_fae(ps_data); + return; +} + + +static enum hrtimer_restart stk_ps_tune0_timer_func(struct hrtimer *timer) +{ + struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, ps_tune0_timer); + queue_work(ps_data->stk_ps_tune0_wq, &ps_data->stk_ps_tune0_work); + hrtimer_forward_now(&ps_data->ps_tune0_timer, ps_data->ps_tune0_delay); + return HRTIMER_RESTART; +} +#endif + +#ifdef STK_POLL_ALS +static enum hrtimer_restart stk_als_timer_func(struct hrtimer *timer) +{ + struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, als_timer); + queue_work(ps_data->stk_als_wq, &ps_data->stk_als_work); + hrtimer_forward_now(&ps_data->als_timer, ps_data->als_poll_delay); + return HRTIMER_RESTART; + +} + +static void stk_als_poll_work_func(struct work_struct *work) +{ + struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_als_work); + int32_t reading = 0, reading_lux, flag_reg; +#ifdef STK_IRS + int ret; +#endif +#ifdef STK_GES + if(ps_data->ges_enabled) + { + input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last); + input_sync(ps_data->als_input_dev); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: ges_enabled=1, als input event %d lux\n",__func__, ps_data->als_lux_last); + return; +#endif + } +#endif + + flag_reg = stk3x1x_get_flag(ps_data); + if(flag_reg < 0) + return; + if(!(flag_reg&STK_FLG_ALSDR_MASK)) + { + //printk(KERN_INFO "%s: als is not ready\n", __func__); + return; + } + +#ifdef STK_IRS + ret = stk_als_ir_skip_als(ps_data); + if(ret == 1) + return; +#endif + + reading = stk3x1x_get_als_reading(ps_data); + if(reading < 0) + return; + // printk("%s: als_data_index=%d, als_data=%d\n", __func__, ps_data->als_data_index, reading); +#ifdef STK_IRS + stk_als_ir_get_corr(ps_data, reading); + reading = reading * ps_data->als_correct_factor / 1000; +#endif + reading_lux = stk_alscode2lux(ps_data, reading); + if(abs(ps_data->als_lux_last - reading_lux) >= STK_ALS_CHANGE_THD) + { + ps_data->als_lux_last = reading_lux; + input_report_abs(ps_data->als_input_dev, ABS_MISC, reading_lux); + input_sync(ps_data->als_input_dev); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: als input event %d lux\n",__func__, reading_lux); +#endif + } + +#ifdef STK_IRS + stk_als_ir_run(ps_data); +#endif + return; +} +#endif /* #ifdef STK_POLL_ALS */ + + +#ifdef STK_POLL_PS +static enum hrtimer_restart stk_ps_timer_func(struct hrtimer *timer) +{ + struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, ps_timer); + queue_work(ps_data->stk_ps_wq, &ps_data->stk_ps_work); + hrtimer_forward_now(&ps_data->ps_timer, ps_data->ps_poll_delay); + return HRTIMER_RESTART; +} + +static void stk_ps_poll_work_func(struct work_struct *work) +{ + struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_ps_work); + uint32_t reading; + int32_t near_far_state; + uint8_t org_flag_reg; +#ifdef STK_GES + int32_t ret; + //uint8_t disable_flag = 0; + uint8_t disable_flag2 = 0, org_flag2_reg; + if(ps_data->ges_enabled == 2) + { + ret = stk3x1x_get_flag2(ps_data); + if(ret < 0) + goto err_i2c_rw; + org_flag2_reg = ret; + + disable_flag2 = org_flag2_reg & (STK_FLG2_INT_GS_MASK | + STK_FLG2_GS10_MASK | STK_FLG2_GS01_MASK); + if(org_flag2_reg & STK_FLG2_GS10_MASK) + { + printk(KERN_INFO "%s: >>>>>>>>>>>>\n", __func__); + } + if(org_flag2_reg & STK_FLG2_GS01_MASK) + { + printk(KERN_INFO "%s: <<<<<<<<<<<<\n", __func__); + } + atomic_set(&ps_data->gesture2, (disable_flag2 & + (STK_FLG2_GS10_MASK | STK_FLG2_GS01_MASK))); + + if(disable_flag2) + { + ret = stk3x1x_set_flag2(ps_data, org_flag2_reg, disable_flag2); + if(ret < 0) + goto err_i2c_rw; + } + } +#endif + + if(ps_data->ps_enabled) + { +#ifdef STK_TUNE0 + // if(!(ps_data->psi_set)) + // return; +#endif + org_flag_reg = stk3x1x_get_flag(ps_data); + if(org_flag_reg < 0) + goto err_i2c_rw; + + if(!(org_flag_reg&STK_FLG_PSDR_MASK)) + { + //printk(KERN_INFO "%s: ps is not ready\n", __func__); + return; + } + + near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0; + reading = stk3x1x_get_ps_reading(ps_data); + if(ps_data->ps_distance_last != near_far_state) + { + ps_data->ps_distance_last = near_far_state; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading); +#endif + } + // ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag); + // if(ret < 0) + // goto err_i2c_rw; + return; + } + +err_i2c_rw: + msleep(30); + return; +} +#endif + +#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) +static void stk_work_func(struct work_struct *work) +{ + uint32_t reading; +#if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02)) + int32_t ret; + uint8_t disable_flag = 0; + int32_t org_flag_reg; +#endif /* #if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02)) */ + +#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD + uint32_t nLuxIndex; +#endif + struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_work); + int32_t near_far_state; + int32_t als_comperator; +#ifdef STK_GES + uint8_t disable_flag2 = 0, org_flag2_reg; +#endif + +#if (STK_INT_PS_MODE == 0x03) + near_far_state = gpio_get_value(ps_data->int_pin); +#elif (STK_INT_PS_MODE == 0x02) + near_far_state = !(gpio_get_value(ps_data->int_pin)); +#endif + +#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02)) + ps_data->ps_distance_last = near_far_state; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + reading = stk3x1x_get_ps_reading(ps_data); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading); +#endif +#else + /* mode 0x01 or 0x04 */ + org_flag_reg = stk3x1x_get_flag(ps_data); + if(org_flag_reg < 0) + goto err_i2c_rw; + + if (org_flag_reg & STK_FLG_ALSINT_MASK) + { + disable_flag |= STK_FLG_ALSINT_MASK; + reading = stk3x1x_get_als_reading(ps_data); + if(reading < 0) + { + printk(KERN_ERR "%s: stk3x1x_get_als_reading fail, ret=%d", __func__, reading); + goto err_i2c_rw; + } +#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD + nLuxIndex = stk_get_lux_interval_index(reading); + stk3x1x_set_als_thd_h(ps_data, code_threshold_table[nLuxIndex]); + stk3x1x_set_als_thd_l(ps_data, code_threshold_table[nLuxIndex-1]); +#else + stk_als_set_new_thd(ps_data, reading); +#endif //CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD + + if(ps_data->ir_code) + { + if(reading < STK_IRC_MAX_ALS_CODE && reading > STK_IRC_MIN_ALS_CODE && + ps_data->ir_code > STK_IRC_MIN_IR_CODE) + { + als_comperator = reading * STK_IRC_ALS_NUMERA / STK_IRC_ALS_DENOMI; + if(ps_data->ir_code > als_comperator) + ps_data->als_correct_factor = STK_IRC_ALS_CORREC; + else + ps_data->als_correct_factor = 1000; + } + printk(KERN_INFO "%s: als=%d, ir=%d, als_correct_factor=%d", __func__, reading, ps_data->ir_code, ps_data->als_correct_factor); + ps_data->ir_code = 0; + } + + reading = reading * ps_data->als_correct_factor / 1000; + + ps_data->als_lux_last = stk_alscode2lux(ps_data, reading); + input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last); + input_sync(ps_data->als_input_dev); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last); +#endif + } + if (org_flag_reg & STK_FLG_PSINT_MASK) + { + disable_flag |= STK_FLG_PSINT_MASK; + near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0; + + ps_data->ps_distance_last = near_far_state; + input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); + input_sync(ps_data->ps_input_dev); + wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); + reading = stk3x1x_get_ps_reading(ps_data); +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading); +#endif + } + + if(disable_flag) + { + ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag); + if(ret < 0) + goto err_i2c_rw; + } +#endif + usleep_range(1000, 2000); + //msleep(1); + enable_irq(ps_data->irq); + return; + +err_i2c_rw: + msleep(30); + enable_irq(ps_data->irq); + return; +} + +static irqreturn_t stk_oss_irq_handler(int irq, void *data) +{ + struct stk3x1x_data *pData = data; + disable_irq_nosync(irq); + queue_work(pData->stk_wq,&pData->stk_work); + return IRQ_HANDLED; +} +#endif /* #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) */ + +#ifdef STK_POLL_ALS +static void stk3x1x_als_set_poll_delay(struct stk3x1x_data *ps_data) +{ + uint8_t als_it = ps_data->alsctrl_reg & 0x0F; + + if(als_it == 0x8) + { + ps_data->als_poll_delay = ns_to_ktime(60 * NSEC_PER_MSEC); + } + else if(als_it == 0x9) + { + ps_data->als_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC); + } + else if(als_it == 0xA) + { + ps_data->als_poll_delay = ns_to_ktime(220 * NSEC_PER_MSEC); + } + else if(als_it == 0xB) + { + ps_data->als_poll_delay = ns_to_ktime(440 * NSEC_PER_MSEC); + } + else if(als_it == 0xC) + { + ps_data->als_poll_delay = ns_to_ktime(880 * NSEC_PER_MSEC); + } + else + { + ps_data->als_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC); + printk(KERN_INFO "%s: unknown ALS_IT=%d, set als_poll_delay=110ms\n", __func__, als_it); + } +} +#endif + +static int32_t stk3x1x_init_all_setting(struct i2c_client *client, struct stk3x1x_platform_data *plat_data) +{ + int32_t ret; + struct stk3x1x_data *ps_data = i2c_get_clientdata(client); + + ret = stk3x1x_software_reset(ps_data); + if(ret < 0) + return ret; + + ret = stk3x1x_check_pid(ps_data); + if(ret < 0) + return ret; + stk3x1x_proc_plat_data(ps_data, plat_data); + ret = stk3x1x_init_all_reg(ps_data); + if(ret < 0) + return ret; +#ifdef STK_POLL_ALS + stk3x1x_als_set_poll_delay(ps_data); +#endif + ps_data->als_enabled = false; + ps_data->ps_enabled = false; + ps_data->re_enable_als = false; + ps_data->re_enable_ps = false; + ps_data->ir_code = 0; + ps_data->als_correct_factor = 1000; + ps_data->first_boot = true; +#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD + stk_init_code_threshold_table(ps_data); +#endif +#ifdef STK_TUNE0 + #ifdef QUALCOMM_PLATFORM + ps_data->tune_zero_init_proc = false; + ps_data->psi_set = 0; + #else + stk_ps_tune_zero_init(ps_data); + #endif +#endif +#ifdef STK_ALS_FIR + memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); + atomic_set(&ps_data->firlength, STK_FIR_LEN); +#endif + atomic_set(&ps_data->recv_reg, 0); +#ifdef STK_GES + ps_data->re_enable_ges = 0; + atomic_set(&ps_data->gesture2, 0); + //memset(stk_ges_op, 0, sizeof(stk_ges_op)); +#endif +#ifdef STK_IRS + ps_data->als_data_index = 0; +#endif + ps_data->ps_distance_last = 1; + ps_data->als_code_last = 0; + return 0; +} + +#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) +static int stk3x1x_setup_irq(struct i2c_client *client) +{ + int irq, err = -EIO; + struct stk3x1x_data *ps_data = i2c_get_clientdata(client); + +//#ifdef SPREADTRUM_PLATFORM +// irq = sprd_alloc_gpio_irq(ps_data->int_pin); +//#else + irq = gpio_to_irq(ps_data->int_pin); +//#endif +#ifdef STK_DEBUG_PRINTF + printk(KERN_INFO "%s: int pin #=%d, irq=%d\n",__func__, ps_data->int_pin, irq); +#endif + if (irq <= 0) + { + printk(KERN_ERR "irq number is not specified, irq # = %d, int pin=%d\n",irq, ps_data->int_pin); + return irq; + } + ps_data->irq = irq; + err = gpio_request(ps_data->int_pin,"stk-int"); + if(err < 0) + { + printk(KERN_ERR "%s: gpio_request, err=%d", __func__, err); + return err; + } + err = gpio_direction_input(ps_data->int_pin); + if(err < 0) + { + printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, err); + return err; + } +#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02)) + err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, DEVICE_NAME, ps_data); +#else + err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_LOW|IRQF_NO_SUSPEND|IRQF_ONESHOT, DEVICE_NAME, ps_data); +#endif + if (err < 0) + { + printk(KERN_WARNING "%s: request_any_context_irq(%d) failed for (%d)\n", __func__, irq, err); + goto err_request_any_context_irq; + } + disable_irq(irq); + + return 0; +err_request_any_context_irq: +//#ifdef SPREADTRUM_PLATFORM +// sprd_free_gpio_irq(ps_data->int_pin); +//#else + gpio_free(ps_data->int_pin); +//#endif + return err; +} +#endif + + +static int stk3x1x_suspend(struct device *dev) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); +#if (defined(STK_CHK_REG) || !defined(STK_POLL_PS)) + int err; +#endif + +#ifndef STK_POLL_PS + struct i2c_client *client = to_i2c_client(dev); +#endif + + printk(KERN_INFO "%s", __func__); +#ifndef SPREADTRUM_PLATFORM + mutex_lock(&ps_data->io_lock); +#endif +#ifdef STK_CHK_REG + err = stk3x1x_validate_n_handle(ps_data->client); + if(err < 0) + { + printk(KERN_ERR "stk3x1x_validate_n_handle fail: %d\n", err); + } + else if (err == 0xFF) + { + if(ps_data->ps_enabled) + stk3x1x_enable_ps(ps_data, 1, 0); + } +#endif /* #ifdef STK_CHK_REG */ +#ifdef STK_GES + if(ps_data->ges_enabled == 1) + { + ps_data->re_enable_ges = ps_data->ges_enabled; + stk3x1x_enable_ges(ps_data, 0, 1); + } + else if(ps_data->ges_enabled == 2) + { + ps_data->re_enable_ges = ps_data->ges_enabled; + stk3x1x_enable_ges(ps_data, 0, 2); + } +#endif +#ifndef SPREADTRUM_PLATFORM + if(ps_data->als_enabled) + { + printk(KERN_INFO "%s: Enable ALS : 0\n", __func__); + stk3x1x_enable_als(ps_data, 0); + ps_data->re_enable_als = true; + } +#endif + if(ps_data->ps_enabled) + { +#ifdef STK_POLL_PS + wake_lock(&ps_data->ps_nosuspend_wl); +#else + if(device_may_wakeup(&client->dev)) + { + err = enable_irq_wake(ps_data->irq); + if (err) + printk(KERN_WARNING "%s: set_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err); + } + else + { + printk(KERN_ERR "%s: not support wakeup source", __func__); + } +#endif + } +#ifndef SPREADTRUM_PLATFORM + mutex_unlock(&ps_data->io_lock); +#endif + return 0; +} + +static int stk3x1x_resume(struct device *dev) +{ + struct stk3x1x_data *ps_data = dev_get_drvdata(dev); +#if (defined(STK_CHK_REG) || !defined(STK_POLL_PS)) + int err; +#endif + +#ifndef STK_POLL_PS + struct i2c_client *client = to_i2c_client(dev); +#endif + printk("%s called\n", __func__); + printk(KERN_INFO "%s", __func__); +#ifndef SPREADTRUM_PLATFORM + mutex_lock(&ps_data->io_lock); +#endif +#ifdef STK_CHK_REG + err = stk3x1x_validate_n_handle(ps_data->client); + if(err < 0) + { + printk(KERN_ERR "stk3x1x_validate_n_handle fail: %d\n", err); + } + else if (err == 0xFF) + { + if(ps_data->ps_enabled) + stk3x1x_enable_ps(ps_data, 1, 0); + } +#endif /* #ifdef STK_CHK_REG */ +#ifdef STK_GES + if(ps_data->re_enable_ges == 1) + { + stk3x1x_enable_ges(ps_data, 1, 1); + ps_data->re_enable_ges = 0; + } + else if(ps_data->re_enable_ges == 2) + { + stk3x1x_enable_ges(ps_data, 1, 2); + ps_data->re_enable_ges = 0; + } +#endif +#ifndef SPREADTRUM_PLATFORM + if(ps_data->re_enable_als) + { + printk(KERN_INFO "%s: Enable ALS : 1\n", __func__); + stk3x1x_enable_als(ps_data, 1); + ps_data->re_enable_als = false; + } +#endif + if(ps_data->ps_enabled) + { +#ifdef STK_POLL_PS + wake_unlock(&ps_data->ps_nosuspend_wl); +#else + if(device_may_wakeup(&client->dev)) + { + err = disable_irq_wake(ps_data->irq); + if (err) + printk(KERN_WARNING "%s: disable_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err); + } +#endif + } +#ifndef SPREADTRUM_PLATFORM + mutex_unlock(&ps_data->io_lock); +#endif + return 0; +} + +static const struct dev_pm_ops stk3x1x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stk3x1x_suspend, stk3x1x_resume) +}; + +//#ifdef CONFIG_HAS_EARLYSUSPEND +#if 0 +static void stk3x1x_early_suspend(struct early_suspend *h) +{ + +} + +static void stk3x1x_late_resume(struct early_suspend *h) +{ + +} +#endif //#ifdef CONFIG_HAS_EARLYSUSPEND + + +#ifdef STK_QUALCOMM_POWER_CTRL +static int stk3x1x_power_ctl(struct stk3x1x_data *data, bool on) +{ + int ret = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio disable failed ret=%d\n", ret); + regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + printk(KERN_INFO "%s: disable stk3x1x power", __func__); + dev_dbg(&data->client->dev, "stk3x1x_power_ctl on=%d\n", + on); + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio enable failed ret=%d\n", ret); + regulator_disable(data->vdd); + return ret; + } + data->power_enabled = on; + printk(KERN_INFO "%s: enable stk3x1x power", __func__); + dev_dbg(&data->client->dev, "stk3x1x_power_ctl on=%d\n", + on); + } else { + dev_warn(&data->client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return ret; +} + +static int stk3x1x_power_init(struct stk3x1x_data *data, bool on) +{ + int ret; + + if (!on) { + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, + 0, STK3X1X_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, + 0, STK3X1X_VIO_MAX_UV); + + regulator_put(data->vio); + } else { + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + STK3X1X_VDD_MIN_UV, + STK3X1X_VDD_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->client->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + STK3X1X_VIO_MIN_UV, + STK3X1X_VIO_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, STK3X1X_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + +static int stk3x1x_device_ctl(struct stk3x1x_data *ps_data, bool enable) +{ + int ret; + struct device *dev = &ps_data->client->dev; + + if (enable && !ps_data->power_enabled) { + ret = stk3x1x_power_ctl(ps_data, true); + if (ret) { + dev_err(dev, "Failed to enable device power\n"); + goto err_exit; + } + ret = stk3x1x_init_all_setting(ps_data->client, ps_data->pdata); + if (ret < 0) { + stk3x1x_power_ctl(ps_data, false); + dev_err(dev, "Failed to re-init device setting\n"); + goto err_exit; + } + } else if (!enable && ps_data->power_enabled) { + #ifdef STK_GES + if (!ps_data->als_enabled && !ps_data->ps_enabled && !ps_data->ges_enabled) { + #else + if (!ps_data->als_enabled && !ps_data->ps_enabled) { + #endif + ret = stk3x1x_power_ctl(ps_data, false); + if (ret) { + dev_err(dev, "Failed to disable device power\n"); + goto err_exit; + } + } else { + dev_dbg(dev, "device control: als_enabled=%d, ps_enabled=%d\n", + ps_data->als_enabled, ps_data->ps_enabled); + } + } else { + dev_dbg(dev, "device control: enable=%d, power_enabled=%d\n", + enable, ps_data->power_enabled); + } + return 0; + +err_exit: + return ret; +} +#endif /* #ifdef STK_QUALCOMM_POWER_CTRL */ + +#ifdef CONFIG_OF +static int stk3x1x_parse_dt(struct device *dev, + struct stk3x1x_platform_data *pdata) +{ +#if 0 + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + + pdata->int_pin = of_get_named_gpio_flags(np, "stk,irq-gpio", + 0, &pdata->int_flags); + if (pdata->int_pin < 0) { + dev_err(dev, "Unable to read irq-gpio\n"); + return pdata->int_pin; + } + + rc = of_property_read_u32(np, "stk,transmittance", &temp_val); + if (!rc) + pdata->transmittance = temp_val; + else { + dev_err(dev, "Unable to read transmittance\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,state-reg", &temp_val); + if (!rc) + pdata->state_reg = temp_val; + else { + dev_err(dev, "Unable to read state-reg\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,psctrl-reg", &temp_val); + if (!rc) + pdata->psctrl_reg = (u8)temp_val; + else { + dev_err(dev, "Unable to read psctrl-reg\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,alsctrl-reg", &temp_val); + if (!rc) + pdata->alsctrl_reg = (u8)temp_val; + else { + dev_err(dev, "Unable to read alsctrl-reg\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,ledctrl-reg", &temp_val); + if (!rc) + pdata->ledctrl_reg = (u8)temp_val; + else { + dev_err(dev, "Unable to read ledctrl-reg\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,wait-reg", &temp_val); + if (!rc) + pdata->wait_reg = (u8)temp_val; + else { + dev_err(dev, "Unable to read wait-reg\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,ps-thdh", &temp_val); + if (!rc) + pdata->ps_thd_h = (u16)temp_val; + else { + dev_err(dev, "Unable to read ps-thdh\n"); + return rc; + } + + rc = of_property_read_u32(np, "stk,ps-thdl", &temp_val); + if (!rc) + pdata->ps_thd_l = (u16)temp_val; + else { + dev_err(dev, "Unable to read ps-thdl\n"); + return rc; + } + + //pdata->use_fir = of_property_read_bool(np, "stk,use-fir"); +#endif + + return 0; +} +#else +static int stk3x1x_parse_dt(struct device *dev, + struct stk3x1x_platform_data *pdata) +{ + return -ENODEV; +} +#endif /* !CONFIG_OF */ + +static int stk3x1x_set_wq(struct stk3x1x_data *ps_data) +{ +#ifdef STK_POLL_ALS + ps_data->stk_als_wq = create_singlethread_workqueue("stk_als_wq"); + INIT_WORK(&ps_data->stk_als_work, stk_als_poll_work_func); + hrtimer_init(&ps_data->als_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ps_data->als_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC); + ps_data->als_timer.function = stk_als_timer_func; +#endif + +#ifdef STK_POLL_PS + ps_data->stk_ps_wq = create_singlethread_workqueue("stk_ps_wq"); + INIT_WORK(&ps_data->stk_ps_work, stk_ps_poll_work_func); + hrtimer_init(&ps_data->ps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ps_data->ps_poll_delay = ns_to_ktime(60 * NSEC_PER_MSEC); + ps_data->ps_timer.function = stk_ps_timer_func; +#endif + +#ifdef STK_TUNE0 + ps_data->stk_ps_tune0_wq = create_singlethread_workqueue("stk_ps_tune0_wq"); + INIT_WORK(&ps_data->stk_ps_tune0_work, stk_ps_tune0_work_func); + hrtimer_init(&ps_data->ps_tune0_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ps_data->ps_tune0_delay = ns_to_ktime(60 * NSEC_PER_MSEC); + ps_data->ps_tune0_timer.function = stk_ps_tune0_timer_func; +#endif + +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + ps_data->stk_wq = create_singlethread_workqueue("stk_wq"); + INIT_WORK(&ps_data->stk_work, stk_work_func); +#endif + return 0; +} + + +static int stk3x1x_set_input_devices(struct stk3x1x_data *ps_data) +{ + int err; + + ps_data->als_input_dev = input_allocate_device(); + if (ps_data->als_input_dev==NULL) + { + printk(KERN_ERR "%s: could not allocate als device\n", __func__); + err = -ENOMEM; + return err; + } + ps_data->ps_input_dev = input_allocate_device(); + if (ps_data->ps_input_dev==NULL) + { + printk(KERN_ERR "%s: could not allocate ps device\n", __func__); + err = -ENOMEM; + return err; + } + ps_data->als_input_dev->name = ALS_NAME; + ps_data->ps_input_dev->name = PS_NAME; + set_bit(EV_ABS, ps_data->als_input_dev->evbit); + set_bit(EV_ABS, ps_data->ps_input_dev->evbit); + input_set_abs_params(ps_data->als_input_dev, ABS_MISC, 0, stk_alscode2lux(ps_data, (1<<16)-1), 0, 0); + input_set_abs_params(ps_data->ps_input_dev, ABS_DISTANCE, 0,1, 0, 0); + err = input_register_device(ps_data->als_input_dev); + if (err<0) + { + printk(KERN_ERR "%s: can not register als input device\n", __func__); + return err; + } + err = input_register_device(ps_data->ps_input_dev); + if (err<0) + { + printk(KERN_ERR "%s: can not register ps input device\n", __func__); + return err; + } + + err = sysfs_create_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group); + if (err < 0) + { + printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__); + return err; + } + err = sysfs_create_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group); + if (err < 0) + { + printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__); + return err; + } + input_set_drvdata(ps_data->als_input_dev, ps_data); + input_set_drvdata(ps_data->ps_input_dev, ps_data); + +#ifdef STK_GES + ps_data->ges_input_dev = input_allocate_device(); + if (ps_data->ges_input_dev==NULL) + { + printk(KERN_ERR "%s: could not allocate ps device\n", __func__); + err = -ENOMEM; + return err; + } + ps_data->ges_input_dev->name = "stk_ges"; + ps_data->ges_input_dev->evbit[0] = BIT_MASK(EV_KEY); + set_bit(KEY_PAGEUP, ps_data->ges_input_dev->keybit); + set_bit(KEY_PAGEDOWN, ps_data->ges_input_dev->keybit); + set_bit(KEY_VOLUMEUP, ps_data->ges_input_dev->keybit); + set_bit(KEY_VOLUMEDOWN, ps_data->ges_input_dev->keybit); + /* + set_bit(KEY_LEFT, ps_data->ges_input_dev->keybit); + set_bit(KEY_RIGHT, ps_data->ges_input_dev->keybit); + set_bit(KEY_UP, ps_data->ges_input_dev->keybit); + set_bit(KEY_DOWN, ps_data->ges_input_dev->keybit); + */ + err = input_register_device(ps_data->ges_input_dev); + if (err<0) + { + printk(KERN_ERR "%s: can not register ps input device\n", __func__); + return err; + } + + err = sysfs_create_group(&ps_data->ges_input_dev->dev.kobj, &stk_ges_attribute_group); + if (err < 0) + { + printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__); + return err; + } + input_set_drvdata(ps_data->ges_input_dev, ps_data); +#endif + + return 0; +} + +static int stk3x1x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = -ENODEV; + struct stk3x1x_data *ps_data; + struct stk3x1x_platform_data *plat_data; + printk(KERN_INFO "%s: driver version = %s\n", __func__, DRIVER_VERSION); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + printk(KERN_ERR "%s: No Support for I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } + + ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL); + if(!ps_data) + { + printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__); + return -ENOMEM; + } + ps_data->client = client; + i2c_set_clientdata(client,ps_data); + mutex_init(&ps_data->io_lock); + wake_lock_init(&ps_data->ps_wakelock,WAKE_LOCK_SUSPEND, "stk_input_wakelock"); + +#ifdef STK_POLL_PS + wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock"); +#endif + + if (client->dev.of_node) { + printk(KERN_INFO "%s: probe with device tree\n", __func__); + plat_data = devm_kzalloc(&client->dev, + sizeof(struct stk3x1x_platform_data), GFP_KERNEL); + if (!plat_data) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + err = stk3x1x_parse_dt(&client->dev, plat_data); +//huanggq + plat_data->state_reg = stk3x1x_pfdata.state_reg; + plat_data->psctrl_reg = stk3x1x_pfdata.psctrl_reg; + plat_data->alsctrl_reg = stk3x1x_pfdata.alsctrl_reg; + plat_data->ledctrl_reg = stk3x1x_pfdata.ledctrl_reg; + plat_data->wait_reg = stk3x1x_pfdata.wait_reg; + plat_data->ps_thd_h = stk3x1x_pfdata.ps_thd_h; + plat_data->ps_thd_l = stk3x1x_pfdata.ps_thd_l; + plat_data->int_pin = stk3x1x_pfdata.int_pin; + plat_data->transmittance = stk3x1x_pfdata.transmittance; +//end + dev_err(&client->dev, + "%s: stk3x1x_parse_dt ret=%d\n", __func__, err); + if (err) + return err; + } else { + printk(KERN_INFO "%s: probe with platform data\n", __func__); +#ifdef SPREADTRUM_PLATFORM + plat_data = &stk3x1x_pfdata; +#else + plat_data = client->dev.platform_data; +#endif + } + if (!plat_data) { + dev_err(&client->dev, + "%s: no stk3x1x platform data!\n", __func__); + goto err_als_input_allocate; + } + ps_data->als_transmittance = plat_data->transmittance; + ps_data->int_pin = plat_data->int_pin; + ps_data->pdata = plat_data; + + if (ps_data->als_transmittance == 0) { + dev_err(&client->dev, + "%s: Please set als_transmittance\n", __func__); + goto err_als_input_allocate; + } + + stk3x1x_set_wq(ps_data); +#ifdef QUALCOMM_PLATFORM + ps_data->ps_thd_h = 0; + ps_data->ps_thd_l = 0; +#endif + ps_data->stk_max_min_diff = STK_MAX_MIN_DIFF; + ps_data->stk_lt_n_ct = STK_LT_N_CT; + ps_data->stk_ht_n_ct = STK_HT_N_CT; + +#ifdef STK_QUALCOMM_POWER_CTRL + err = stk3x1x_power_init(ps_data, true); + if (err) + goto err_init_all_setting; + + err = stk3x1x_power_ctl(ps_data, true); + if (err) + goto err_power_on; + + ps_data->als_enabled = false; + ps_data->ps_enabled = false; +#endif + + err = stk3x1x_init_all_setting(client, plat_data); + if(err < 0) + goto err_init_all_setting; + + err = stk3x1x_set_input_devices(ps_data); + if(err < 0) + goto err_setup_input_device; + +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + err = stk3x1x_setup_irq(client); + if(err < 0) + goto err_stk3x1x_setup_irq; +#endif + device_init_wakeup(&client->dev, true); + +//#ifdef CONFIG_HAS_EARLYSUSPEND +#if 0 + ps_data->stk_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ps_data->stk_early_suspend.suspend = stk3x1x_early_suspend; + ps_data->stk_early_suspend.resume = stk3x1x_late_resume; + register_early_suspend(&ps_data->stk_early_suspend); +#endif + +#ifdef STK_QUALCOMM_POWER_CTRL + /* enable device power only when it is enabled */ + err = stk3x1x_power_ctl(ps_data, false); + if (err) + goto err_stk3x1x_setup_irq; +#endif + printk(KERN_INFO "%s: probe successfully", __func__); + return 0; + + //device_init_wakeup(&client->dev, false); +err_stk3x1x_setup_irq: +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + free_irq(ps_data->irq, ps_data); + //#ifdef SPREADTRUM_PLATFORM + // sprd_free_gpio_irq(ps_data->int_pin); + //#else + gpio_free(ps_data->int_pin); + //#endif +#endif +err_setup_input_device: +#ifdef STK_GES + sysfs_remove_group(&ps_data->ges_input_dev->dev.kobj, &stk_ges_attribute_group); + input_unregister_device(ps_data->ges_input_dev); + input_free_device(ps_data->ges_input_dev); +#endif + sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group); + sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group); + input_unregister_device(ps_data->ps_input_dev); + input_unregister_device(ps_data->als_input_dev); + input_free_device(ps_data->ps_input_dev); + input_free_device(ps_data->als_input_dev); +#ifdef STK_QUALCOMM_POWER_CTRL + stk3x1x_power_ctl(ps_data, false); +err_power_on: + stk3x1x_power_init(ps_data, false); +#endif +err_init_all_setting: +#ifdef STK_POLL_ALS + hrtimer_try_to_cancel(&ps_data->als_timer); + destroy_workqueue(ps_data->stk_als_wq); +#endif +#ifdef STK_TUNE0 + destroy_workqueue(ps_data->stk_ps_tune0_wq); +#endif +#ifdef STK_POLL_PS + hrtimer_try_to_cancel(&ps_data->ps_timer); + destroy_workqueue(ps_data->stk_ps_wq); +#endif +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + destroy_workqueue(ps_data->stk_wq); +#endif +err_als_input_allocate: +#ifdef STK_POLL_PS + wake_lock_destroy(&ps_data->ps_nosuspend_wl); +#endif + wake_lock_destroy(&ps_data->ps_wakelock); + mutex_destroy(&ps_data->io_lock); + kfree(ps_data); + return err; +} + + +static int stk3x1x_remove(struct i2c_client *client) +{ + struct stk3x1x_data *ps_data = i2c_get_clientdata(client); + device_init_wakeup(&client->dev, false); +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + free_irq(ps_data->irq, ps_data); + //#ifdef SPREADTRUM_PLATFORM + // sprd_free_gpio_irq(ps_data->int_pin); + //#else + gpio_free(ps_data->int_pin); + //#endif +#endif /* #if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) */ + + +#ifdef STK_GES + sysfs_remove_group(&ps_data->ges_input_dev->dev.kobj, &stk_ges_attribute_group); + input_unregister_device(ps_data->ges_input_dev); + input_free_device(ps_data->ges_input_dev); +#endif +#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) + destroy_workqueue(ps_data->stk_wq); +#endif + sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group); + sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group); + input_unregister_device(ps_data->ps_input_dev); + input_unregister_device(ps_data->als_input_dev); + input_free_device(ps_data->ps_input_dev); + input_free_device(ps_data->als_input_dev); +#ifdef STK_QUALCOMM_POWER_CTRL + stk3x1x_power_ctl(ps_data, false); + stk3x1x_power_init(ps_data, false); +#endif +#ifdef STK_POLL_ALS + hrtimer_try_to_cancel(&ps_data->als_timer); + destroy_workqueue(ps_data->stk_als_wq); +#endif +#ifdef STK_TUNE0 + destroy_workqueue(ps_data->stk_ps_tune0_wq); +#endif +#ifdef STK_POLL_PS + hrtimer_try_to_cancel(&ps_data->ps_timer); + destroy_workqueue(ps_data->stk_ps_wq); + wake_lock_destroy(&ps_data->ps_nosuspend_wl); +#endif + wake_lock_destroy(&ps_data->ps_wakelock); + mutex_destroy(&ps_data->io_lock); + kfree(ps_data); + + return 0; +} + +static const struct i2c_device_id stk_ps_id[] = +{ + { "stk_ps", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stk_ps_id); + +static struct of_device_id stk_match_table[] = { + { .compatible = "stk,stk3x1x", }, + { }, +}; + +static struct i2c_driver stk_ps_driver = +{ + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = stk_match_table, +#endif + .pm = &stk3x1x_pm_ops, + }, + .probe = stk3x1x_probe, + .remove = stk3x1x_remove, + .id_table = stk_ps_id, +}; + +static int __init stk3x1x_init(void) +{ + int ret; + + printk("stk3x1x_init"); + + ret = i2c_add_driver(&stk_ps_driver); + if (ret) + { + i2c_del_driver(&stk_ps_driver); + return ret; + } + return 0; +} + +static void __exit stk3x1x_exit(void) +{ + i2c_del_driver(&stk_ps_driver); +} + +module_init(stk3x1x_init); +module_exit(stk3x1x_exit); +MODULE_AUTHOR("Lex Hsieh "); +MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); \ No newline at end of file -- cgit v1.3.1