/* * stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x * proximity/ambient light sensor * * Copyright (C) 2012~2013 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 #include #include #include #include #include #include #include #include #include #include #include #include "../init-input.h" #include "stk3x1x.h" #include #include #ifdef CONFIG_SCENELOCK #include #endif /* *added by guoying */ #include /* *ended by guoying */ #undef CONFIG_HAS_EARLYSUSPEND /*#include */ #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif #ifdef CONFIG_PM #include #endif #define DRIVER_VERSION "3.5.2" #define KEY_PROX_NEAR 249 #define KEY_PROX_FAR 250 /* Driver Settings */ #define CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD #ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD #define STK_ALS_CHANGE_THD 20 /* The threshold to trigger ALS interrupt, unit: lux */ #endif #define STK_INT_PS_MODE 1 /* 1, 2, or 3 */ #define STK_POLL_PS /* ALS interrupt is valid only when STK_INT_PS_MODE = 1 or 4*/ #define STK_POLL_ALS #define STK_TUNE0 /*#define STK_DEBUG_PRINTF #define STK_ALS_FIR #define STK_IRS */ #define STK_CHK_REG #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 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 /* misc define */ #define MIN_ALS_POLL_DELAY_NS 20000000 #define STK2213_PID 0x23 #define STK3010_PID 0x33 #define STK3311_9_BLK_PID 0x11 #define STK3311_8_PID 0x12 #define STK3210_STK3310_PID 0x13 #define STK3311_9_PID 0x15 #define STK2213C_PID 0x24 #define STK3210C_PID 0x18 #define STK3311_9C_PID 0x19 #define STK3311_8C_PID 0x1A #define STK3310C_PID 0x1B #define STK3310SA_PID 0x17 #define STK3311SA_PID 0x1E #define STK3311WV_PID 0x1D #ifdef STK_TUNE0 #define STK_MAX_MIN_DIFF 200 #define STK_LT_N_CT 100 #define STK_HT_N_CT 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 748 #define DEVICE_NAME "stk3x1x" #define ALS_NAME "stk3x1x_ls" #define PS_NAME "stk3x1x_ps" static struct stk3x1x_platform_data stk3x1x_pfdata = { .state_reg = 0x0, /* disable all */ .psctrl_reg = 0x71, /* ps_persistance=4, ps_gain=64X, PS_IT=0.391ms */ .alsctrl_reg = 0x38, /* als_persistance=1, als_gain=64X, ALS_IT=50ms */ .ledctrl_reg = 0xFF, /* 100mA IRDR, 64/64 LED duty */ .wait_reg = 0x07, /* 50 ms */ .ps_thd_h = 1700, .ps_thd_l = 1500, .int_pin = 0, /* sprd_3rdparty_gpio_pls_irq*/ .transmittance = 500, }; #ifdef STK_ALS_FIR #define STK_FIR_LEN 8 #define MAX_FIR_LEN 32 struct data_filter { u16 raw[MAX_FIR_LEN]; int sum; int number; int idx; }; #endif struct stk3x1x_data { struct i2c_client *client; #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; struct mutex io_lock; struct input_dev *ps_input_dev; int32_t ps_distance_last; int32_t ps_near_state_last; bool ps_enabled; bool re_enabled_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; #endif #ifdef STK_ALS_FIR struct data_filter fir; atomic_t firlength; #endif atomic_t recv_reg; }; #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 u32 debug_mask; static struct sensor_config_info ls_sensor_info = { .input_type = LS_TYPE, .int_number = 0, .ldo = NULL, }; enum { DEBUG_INIT = 1U << 0, DEBUG_REPORT_ALS_DATA = 1U << 1, DEBUG_REPORT_PS_DATA = 1U << 2, DEBUG_SUSPEND = 1U << 3, DEBUG_CONTROL_INFO = 1U << 4, DEBUG_INT = 1U << 5, }; #define dprintk(level_mask, fmt, arg...) {if (unlikely(debug_mask & level_mask)) \ printk("*stk3x1x:*" fmt , ## arg); } 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); #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 const unsigned short normal_i2c[2] = {0x48, I2C_CLIENT_END}; static int stk_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; if (ls_sensor_info.twi_id == adapter->nr) { printk("%s: ===========addr= %x\n", __func__, client->addr); strlcpy(info->type, DEVICE_NAME, I2C_NAME_SIZE); return 0; } else { return -ENODEV; } } 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); } 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; 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; } inline 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 < LUX_THD_TABLE_SIZE; i++, j++) { alscode = stk_lux2alscode(ps_data, lux_threshold_table[j]); printk(KERN_INFO "alscode[%d]=%d\n", i, alscode); code_threshold_table[i] = (uint16_t)(alscode); } code_threshold_table[i] = 0xffff; printk(KERN_INFO "alscode[%d]=%d\n", i, alscode); } static uint32_t stk_get_lux_interval_index(uint16_t alscode) { uint32_t i; for (i = 1; i <= LUX_THD_TABLE_SIZE; i++) { if ((alscode >= code_threshold_table[i-1]) && (alscode < code_threshold_table[i])) return i; } return LUX_THD_TABLE_SIZE; } #else void stk_als_set_new_thd(struct stk3x1x_data *ps_data, uint16_t alscode) { int32_t high_thd, low_thd; high_thd = alscode + stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD); low_thd = alscode - stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD); if (high_thd >= (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; 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 ps_data->ps_thd_h = plat_data->ps_thd_h; ps_data->ps_thd_l = 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; #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; } return 0; } static int32_t stk3x1x_check_pid(struct stk3x1x_data *ps_data) { unsigned char value[2]; int err; 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]); if (value[1] == 0xC0) printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__); switch (value[0]) { case STK2213_PID: case STK3010_PID: case STK3311_9_BLK_PID: case STK3311_8_PID: case STK3210_STK3310_PID: case STK3311_9_PID: case STK2213C_PID: case STK3210C_PID: case STK3311_9C_PID: case STK3311_8C_PID: case STK3310C_PID: case STK3310SA_PID: case STK3311SA_PID: case STK3311WV_PID: return 0; case 0x0: printk(KERN_ERR "PID=0x0, please make sure the chip is stk3x1x!\n"); return -2; 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; } msleep(1); 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; } 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; dprintk(DEBUG_CONTROL_INFO, "%s data === %d\n", __func__, enable); #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 */ 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_i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG); if (ret < 0) { printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret); 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_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret); return ret; } if (enable) { printk(KERN_INFO "%s: HT=%d,LT=%d\n", __func__, ps_data->ps_thd_h, ps_data->ps_thd_l); #ifdef STK_TUNE0 if (!(ps_data->psi_set)) hrtimer_start(&ps_data->ps_tune0_timer, ps_data->ps_tune0_delay, HRTIMER_MODE_REL); #endif #ifdef STK_POLL_PS hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL); ps_data->ps_distance_last = -1; ps_data->ps_near_state_last = 0; #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); /*support wake lock for ps 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 */ { msleep(4); 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); /*support wake lock for ps*/ /*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); */ printk(KERN_ERR "%s: //disable_irq(ps_data->irq);\n", __func__); #endif ps_data->ps_enabled = false; } 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; dprintk(DEBUG_CONTROL_INFO, "%s data === %d\n", __func__, enable); if (curr_als_enable == enable) return 0; #ifdef STK_IRS if (enable && !(ps_data->ps_enabled)) { ret = stk3x1x_get_ir_reading(ps_data); if (ret > 0) ps_data->ir_code = ret; } #endif #ifndef STK_POLL_ALS if (enable) { stk3x1x_set_als_thd_h(ps_data, 0x0000); stk3x1x_set_als_thd_l(ps_data, 0xFFFF); } #endif 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_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_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; } 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 } 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 } return ret; } static int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data) { int32_t word_data; #ifdef STK_ALS_FIR int index; int firlen = atomic_read(&ps_data->firlength); #endif 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; } word_data = (value[0] << 8) | value[1]; #ifdef STK_ALS_FIR if (ps_data->fir.number < firlen) { ps_data->fir.raw[ps_data->fir.number] = word_data; ps_data->fir.sum += word_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] = word_data; ps_data->fir.sum += word_data; ps_data->fir.idx++; word_data = ps_data->fir.sum/firlen; } #endif return word_data; } static int32_t stk3x1x_set_irs_it_slp(struct stk3x1x_data *ps_data, uint16_t *slp_time) { uint8_t irs_alsctrl; int32_t ret; irs_alsctrl = (ps_data->alsctrl_reg & 0x0F) - 2; switch (irs_alsctrl) { case 6: *slp_time = 12; break; case 7: *slp_time = 24; break; case 8: *slp_time = 48; break; case 9: *slp_time = 96; 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 word_data, ret; uint8_t w_reg, retry = 0; uint16_t irs_slp_time = 100; bool re_enable_ps = false; unsigned char value[2]; if (ps_data->ps_enabled) { #ifdef STK_TUNE0 if (!(ps_data->psi_set)) { hrtimer_cancel(&ps_data->ps_tune0_timer); cancel_work_sync(&ps_data->stk_ps_tune0_work); } #endif stk3x1x_enable_ps(ps_data, 0, 1); re_enable_ps = true; } ret = stk3x1x_set_irs_it_slp(ps_data, &irs_slp_time); if (ret < 0) goto irs_err_i2c_rw; 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__); goto irs_err_i2c_rw; } w_reg = ret | STK_STATE_EN_IRS_MASK; ret = stk3x1x_i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); goto irs_err_i2c_rw; } msleep(irs_slp_time); do { msleep(3); 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 300ms\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]); 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; } if (re_enable_ps) stk3x1x_enable_ps(ps_data, 1, 1); return word_data; irs_err_i2c_rw: if (re_enable_ps) stk3x1x_enable_ps(ps_data, 1, 1); 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; } if (value[1] != ps_data->alsctrl_reg) { 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; reading = stk3x1x_get_als_reading(ps_data); 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 enable, ret; mutex_lock(&ps_data->io_lock); enable = (ps_data->als_enabled) ? 1 : 0; mutex_unlock(&ps_data->io_lock); ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG); ret = (ret & STK_STATE_EN_ALS_MASK) ? 1 : 0; if (enable != ret) printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret); 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_ms(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 value = value * 1000 * 1000; 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); 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 */ 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 enable, ret; struct stk3x1x_data *ps_data = dev_get_drvdata(dev); mutex_lock(&ps_data->io_lock); enable = (ps_data->ps_enabled) ? 1 : 0; mutex_unlock(&ps_data->io_lock); ret = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG); ret = (ret & STK_STATE_EN_PS_MASK) ? 1 : 0; if (enable != ret) printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret); 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_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_ms(ps_data->ps_poll_delay); mutex_unlock(&ps_data->io_lock); return scnprintf(buf, PAGE_SIZE, "%lld\n", delay); } static ssize_t stk_ps_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 ps poll delay=%lld\n", __func__, value); #endif value = value * 1000 * 1000; 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->ps_poll_delay)) ps_data->ps_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_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); /*support wake lock for ps*/ /*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); /*support wake lock for ps*/ /*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; } #if 0 static ssize_t stk_als_lux_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf) { int32_t als_thd_l0_reg, als_thd_l1_reg; struct stk3x1x_data *ps_data = dev_get_drvdata(dev); uint32_t als_lux; als_thd_l0_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_THDL1_ALS_REG); als_thd_l1_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_THDL2_ALS_REG); if (als_thd_l0_reg < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l0_reg); return -EINVAL; } if (als_thd_l1_reg < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l1_reg); return -EINVAL; } als_thd_l0_reg |= (als_thd_l1_reg << 8); als_lux = stk_alscode2lux(ps_data, als_thd_l0_reg); return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux); } static ssize_t stk_als_lux_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; } value = stk_lux2alscode(ps_data, value); stk3x1x_set_als_thd_l(ps_data, value); return size; } static ssize_t stk_als_lux_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf) { int32_t als_thd_h0_reg, als_thd_h1_reg; struct stk3x1x_data *ps_data = dev_get_drvdata(dev); uint32_t als_lux; als_thd_h0_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_THDH1_ALS_REG); als_thd_h1_reg = stk3x1x_i2c_smbus_read_byte_data(ps_data->client, STK_THDH2_ALS_REG); if (als_thd_h0_reg < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h0_reg); return -EINVAL; } if (als_thd_h1_reg < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h1_reg); return -EINVAL; } als_thd_h0_reg |= (als_thd_h1_reg << 8); als_lux = stk_alscode2lux(ps_data, als_thd_h0_reg); return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux); } static ssize_t stk_als_lux_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; } value = stk_lux2alscode(ps_data, value); stk3x1x_set_als_thd_h(ps_data, value); return size; } #endif 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); ret = kstrtoul(buf, 16, &value); if (ret < 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, " "); ret = kstrtoul(token[0], 16, (unsigned long *)&(addr)); if (ret < 0) { printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); return ret; } ret = kstrtoul(token[1], 16, (unsigned long *)&(cmd)); if (ret < 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); return 0; } #endif /* #ifdef STK_TUNE0 */ static struct device_attribute als_enable_attribute = __ATTR(enable, 0660, 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); #if 0 static struct device_attribute als_lux_thd_l_attribute = __ATTR(luxthdl, 0664, stk_als_lux_thd_l_show, stk_als_lux_thd_l_store); static struct device_attribute als_lux_thd_h_attribute = __ATTR(luxthdh, 0664, stk_als_lux_thd_h_show, stk_als_lux_thd_h_store); #endif static struct device_attribute als_poll_delay_attribute = __ATTR(ls_poll_delay, 0660, 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, #if 0 &als_lux_thd_l_attribute.attr, &als_lux_thd_h_attribute.attr, #endif &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 = { .name = "driver", .attrs = stk_als_attrs, }; */ static struct device_attribute ps_enable_attribute = __ATTR(enable, 0660, stk_ps_enable_show, stk_ps_enable_store); static struct device_attribute ps_delay_attribute = __ATTR(ps_poll_delay, 0660, stk_ps_delay_show, stk_ps_delay_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 recv_attribute = __ATTR(recv, 0664, stk_recv_show, stk_recv_store); static struct device_attribute 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); #endif static struct attribute *stk_ps_attrs[] = { &ps_enable_attribute.attr, &ps_delay_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, &recv_attribute.attr, &send_attribute.attr, &all_reg_attribute.attr, &status_attribute.attr, #ifdef STK_TUNE0 &ps_cali_attribute.attr, #endif NULL }; /* static struct attribute_group stk_ps_attribute_group = { .name = "driver", .attrs = stk_ps_attrs, };*/ #ifdef STK_TUNE0 static int stk_ps_tune_zero_val(struct stk3x1x_data *ps_data) { int mode; int32_t word_data, lii; 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]); 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; } 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]; ps_data->ps_thd_h = ps_data->ps_stat_data[1] + STK_HT_N_CT; ps_data->ps_thd_l = ps_data->ps_stat_data[1] + STK_LT_N_CT; 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_tune_zero_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->tune_zero_init_proc = true; 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; 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]; if (ps_data->psi_set || !(ps_data->ps_enabled)) 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_tune_zero_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 > STK_MAX_MIN_DIFF) { ps_data->psi_set = ps_data->psi; ps_data->ps_thd_h = ps_data->psi + STK_HT_N_CT; ps_data->ps_thd_l = ps_data->psi + STK_LT_N_CT; 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, reading_lux, als_comperator, flag_reg; flag_reg = stk3x1x_get_flag(ps_data); if (flag_reg < 0) return; if (!(flag_reg&STK_FLG_ALSDR_MASK)) return; reading = stk3x1x_get_als_reading(ps_data); if (reading < 0) return; if (ps_data->ir_code) { ps_data->als_correct_factor = 1000; 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; } #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: als=%d, ir=%d, als_correct_factor=%d", __func__, reading, ps_data->ir_code, ps_data->als_correct_factor); #endif ps_data->ir_code = 0; } reading = reading * ps_data->als_correct_factor / 1000; 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; dprintk(DEBUG_REPORT_ALS_DATA, "lightsensor data = %d\n", 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 } 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; } #define CODE_H_THD 700 #define CODE_L_THD 100 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; int32_t ret; uint8_t disable_flag = 0; #ifdef STK_TUNE0 if (!(ps_data->psi_set) || !(ps_data->ps_enabled)) 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)) 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; dprintk(DEBUG_REPORT_ALS_DATA, "proximity data = %d\n", near_far_state); input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state); input_sync(ps_data->ps_input_dev); /*support wake lock for ps*/ /*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; if (ps_data->ps_near_state_last == 0 && reading > CODE_H_THD) { printk(KERN_INFO "%s: >>>>>>>>>>>>\n", __func__); input_report_key(ps_data->ps_input_dev, KEY_PROX_NEAR, 1); input_sync(ps_data->ps_input_dev); msleep(100); input_report_key(ps_data->ps_input_dev, KEY_PROX_NEAR, 0); input_sync(ps_data->ps_input_dev); ps_data->ps_near_state_last = 1; } if (ps_data->ps_near_state_last == 1 && reading < CODE_L_THD) { printk(KERN_INFO "%s: <<<<<<<<<<<<\n", __func__); input_report_key(ps_data->ps_input_dev, KEY_PROX_FAR, 1); input_sync(ps_data->ps_input_dev); msleep(100); input_report_key(ps_data->ps_input_dev, KEY_PROX_FAR, 0); input_sync(ps_data->ps_input_dev); ps_data->ps_near_state_last = 0; } 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; uint8_t org_flag_reg = 0; #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; #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); /*support wake lock for ps*/ /*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); /*support wake lock for ps*/ /*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); #ifdef STK_DEBUG_PRINTF printk(KERN_INFO "%s: ps input event=%d, 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; /*added by guoying if we are in far away status, asleep the device*/ /*if (near_far_state) { printk(KERN_ERR "%s:object leave before report power key event\n", __func__); input_report_key(ps_data->ps_input_dev, KEY_PROX_SLEEP, 1);*/ input_sync(ps_data->ps_input_dev); msleep(100); /*input_report_key(ps_data->ps_input_dev, KEY_PROX_SLEEP, 0);*/ input_sync(ps_data->ps_input_dev); /*printk(KERN_ERR "%s: object leave after report power key event\n", __func__); }*/ if (!near_far_state) { /*printk(KERN_ERR "%s: object come before report power key event\n", __func__); input_report_key(ps_data->ps_input_dev, KEY_PROX_WAKE, 1);*/ input_sync(ps_data->ps_input_dev); msleep(100); /*input_report_key(ps_data->ps_input_dev, KEY_PROX_WAKE, 0);*/ input_sync(ps_data->ps_input_dev); /*printk(KERN_ERR "%s: object come after report power key event\n", __func__);*/ } } #endif msleep(1); input_set_int_enable(&(ls_sensor_info.input_type), 1); return; err_i2c_rw: msleep(30); input_set_int_enable(&(ls_sensor_info.input_type), 1); return; } /*#include */ #include /*#define PLDATA_INTERRUPT_REG_VADDR SUNXI_R_PIO_VBASE + 0x238*/ static irqreturn_t stk_oss_irq_handler(int irq, void *data) { struct stk3x1x_data *pData = data; input_set_int_enable(&(ls_sensor_info.input_type), 0); /*pr_err("aw==== in the stk_oss_irq_handle:0x%x\n", readl(PLDATA_INTERRUPT_REG_VADDR));*/ queue_work(pData->stk_wq, &pData->stk_work); return IRQ_HANDLED; } #endif /* #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) */ 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); stk3x1x_proc_plat_data(ps_data, plat_data); ret = stk3x1x_software_reset(ps_data); if (ret < 0) return ret; ret = stk3x1x_check_pid(ps_data); if (ret < 0) return ret; ret = stk3x1x_init_all_reg(ps_data); if (ret < 0) return ret; ps_data->als_enabled = false; ps_data->ps_enabled = false; ps_data->re_enable_als = false; ps_data->re_enabled_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 stk_ps_tune_zero_init(ps_data); #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); return 0; } #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) static int stk3x1x_setup_irq(struct i2c_client *client) { int err = -EIO; struct stk3x1x_data *ps_data = i2c_get_clientdata(client); pr_err("aw==== %s:light sensor irq_number= %d\n", __func__, ls_sensor_info.int_number); ls_sensor_info.dev = &(ps_data->ps_input_dev->dev); if (0 != ls_sensor_info.int_number) { err = input_request_int(&(ls_sensor_info.input_type), stk_oss_irq_handler, IRQF_TRIGGER_FALLING, ps_data); if (err) { printk("Failed to request gpio irq \n"); return err; } } err = 0; return err; } #endif #ifdef CONFIG_PM static int stk3x1x_suspend(struct device *dev, pm_message_t mesg) { struct i2c_client *client = to_i2c_client(dev); struct stk3x1x_data *ps_data = i2c_get_clientdata(client); int err; #ifdef CONFIG_SCENELOCK int is_talking_standby; #endif #ifndef STK_POLL_PS /*struct i2c_client *client = to_i2c_client(dev);*/ #endif #if 0 if (NORMAL_STANDBY == standby_type) { /* process for super standby */ } else if (SUPER_STANDBY == standby_type) { if (check_scene_locked(SCENE_TALKING_STANDBY) == 0) { printk("lradc-key: talking standby, enable wakeup source lradc!!\n"); enable_wakeup_src(CPUS_GPIO_SRC, 0); } else { } } return 0; #endif printk(KERN_INFO "%s\n", __func__); mutex_lock(&ps_data->io_lock); #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 if (ps_data->als_enabled) { stk3x1x_enable_als(ps_data, 0); ps_data->re_enable_als = true; } if (ps_data->ps_enabled) { #ifdef STK_POLL_PS /*wake_lock(&ps_data->ps_nosuspend_wl);*/ #ifdef CONFIG_SCENELOCK is_talking_standby = check_scene_locked(SCENE_TALKING_STANDBY); pr_err("check_scene_locked = %d\n", is_talking_standby); if (is_talking_standby != 0) #endif { stk3x1x_enable_ps(ps_data, 0, 1); ps_data->re_enabled_ps = true; pr_err("aw==== in the re enable ps \n"); } #else pr_err("aw==== suspend \n"); if (SUPER_STANDBY == standby_type) { err = enable_wakeup_src(CPUS_GPIO_SRC, 0); 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 } mutex_unlock(&ps_data->io_lock); if (ls_sensor_info.sensor_power_ldo != NULL) { regulator_disable(ls_sensor_info.sensor_power_ldo); } return 0; } static int stk3x1x_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); /*added by guoying*/ uint8_t disable_flag = 0; uint8_t org_flag_reg; int32_t ret; int32_t near_far_state; uint32_t reading; /*ended by guoying*/ #if 0 if (NORMAL_STANDBY == standby_type) { /* process for super standby */ } else if (SUPER_STANDBY == standby_type) { if (check_scene_locked(SCENE_TALKING_STANDBY) != 0) { } else { disable_wakeup_src(CPUS_GPIO_SRC, 0); printk("aw=== ps-key: resume from talking standby!!\n"); } } return 0; #endif if (ls_sensor_info.sensor_power_ldo != NULL) { regulator_enable(ls_sensor_info.sensor_power_ldo); msleep(100); } struct stk3x1x_data *ps_data = i2c_get_clientdata(client); int err; #ifndef STK_POLL_PS /*struct i2c_client *client = to_i2c_client(dev);*/ #endif printk(KERN_INFO "%s\n", __func__); mutex_lock(&ps_data->io_lock); #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 if (ps_data->re_enable_als) { stk3x1x_enable_als(ps_data, 1); ps_data->re_enable_als = false; } if (ps_data->ps_enabled) { #ifdef STK_POLL_PS /*wake_unlock(&ps_data->ps_nosuspend_wl);*/ #else if (SUPER_STANDBY == standby_type) { err = disable_wakeup_src(CPUS_GPIO_SRC, 0); if (err) printk(KERN_WARNING "%s: disable_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err); } #endif } else if (ps_data->re_enabled_ps) { stk3x1x_enable_ps(ps_data, 1 , 1); ps_data->re_enabled_ps = false; } mutex_unlock(&ps_data->io_lock); /* added by guoying */ org_flag_reg = stk3x1x_get_flag(ps_data); if (org_flag_reg & STK_FLG_PSINT_MASK) { printk(KERN_ERR "%s:before stk3x1x_set_flag ,org_flag_reg = 0x%X\n", __func__, org_flag_reg); disable_flag |= STK_FLG_PSINT_MASK; near_far_state = (org_flag_reg & STK_FLG_NF_MASK) ? 1 : 0; reading = stk3x1x_get_ps_reading(ps_data); printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n", __func__, near_far_state, reading); ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag); if (ret < 0) return 0; /*if we are in near status, wake up the device*/ /*if (!near_far_state) { printk(KERN_ERR "%s: object come in resume before report power key event\n", __func__); input_report_key(ps_data->ps_input_dev, KEY_PROX_WAKE, 1);*/ input_sync(ps_data->ps_input_dev); msleep(100); /*input_report_key(ps_data->ps_input_dev, KEY_PROX_WAKE, 0);*/ input_sync(ps_data->ps_input_dev); printk(KERN_ERR "%s: after report power key event\n", __func__); /* } */ } return 0; } #endif #ifdef CONFIG_HAS_EARLYSUSPEND static void stk3x1x_early_suspend(struct early_suspend *h) { struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend); #ifdef CONFIG_SCENELOCK int is_talking_standby; #endif #ifndef STK_POLL_PS int err; #endif printk(KERN_INFO "%s\n", __func__); mutex_lock(&ps_data->io_lock); if (ps_data->als_enabled) { stk3x1x_enable_als(ps_data, 0); ps_data->re_enable_als = true; } if (ps_data->ps_enabled) { #ifdef STK_POLL_PS /* wake_lock(&ps_data->ps_nosuspend_wl);*/ #ifdef CONFIG_SCENELOCK is_talking_standby = check_scene_locked(SCENE_TALKING_STANDBY); dprintk(DEBUG_SUSPEND, "check_scene_locked = %d\n", is_talking_standby); if (is_talking_standby != 0) #endif { stk3x1x_enable_ps(ps_data, 0, 1); ps_data->re_enabled_ps = true; } #else 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); #endif } mutex_unlock(&ps_data->io_lock); return; } static void stk3x1x_late_resume(struct early_suspend *h) { struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend); #ifndef STK_POLL_PS int err; #endif printk(KERN_INFO "%s\n", __func__); mutex_lock(&ps_data->io_lock); if (ps_data->re_enable_als) { stk3x1x_enable_als(ps_data, 1); ps_data->re_enable_als = false; } if (ps_data->ps_enabled) { #ifdef STK_POLL_PS /*wake_unlock(&ps_data->ps_nosuspend_wl);*/ #else 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 } else if (ps_data->re_enabled_ps) { stk3x1x_enable_ps(ps_data, 1 , 1); ps_data->re_enabled_ps = false; } mutex_unlock(&ps_data->io_lock); return; } #endif static int stk3x1x_sysfs_create_files(struct kobject *kobj, struct attribute **attrs) { int err; while (*attrs != NULL) { err = sysfs_create_file(kobj, *attrs); if (err) return err; attrs++; } return 0; } static int stk3x1x_sysfs_remove_files(struct kobject *kobj, struct attribute **attrs) { while (*attrs != NULL) { sysfs_remove_file(kobj, *attrs); attrs++; } 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; /* *added by guoying */ struct gpio_config *pin_cfg = &ls_sensor_info.irq_gpio; char pin_name[SUNXI_PIN_NAME_MAX_LEN]; unsigned long config; /* *ended by guoying */ 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); /*support wake lock for ps*/ /* 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 (&stk3x1x_pfdata != NULL) { plat_data = &stk3x1x_pfdata; ps_data->als_transmittance = plat_data->transmittance; ps_data->int_pin = plat_data->int_pin; if (ps_data->als_transmittance == 0) { printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__); goto err_als_input_allocate; } } else { printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__); goto err_als_input_allocate; } 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; goto err_als_input_allocate; } 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; goto err_ps_input_allocate; } 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); /*added by guoying for wake up system*/ set_bit(EV_KEY, ps_data->ps_input_dev->evbit); set_bit(EV_REL, ps_data->ps_input_dev->evbit); /*set_bit(KEY_POWER, ps_data->ps_input_dev->keybit); set_bit(KEY_PROX_SLEEP, ps_data->ps_input_dev->keybit); set_bit(KEY_PROX_WAKE, ps_data->ps_input_dev->keybit); */ set_bit(EV_KEY, ps_data->ps_input_dev->evbit); set_bit(KEY_PROX_NEAR, ps_data->ps_input_dev->keybit); set_bit(KEY_PROX_FAR, ps_data->ps_input_dev->keybit); 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__); goto err_als_input_register; } err = input_register_device(ps_data->ps_input_dev); if (err < 0) { printk(KERN_ERR "%s: can not register ps input device\n", __func__); goto err_ps_input_register; } err = stk3x1x_sysfs_create_files(&ps_data->als_input_dev->dev.kobj, stk_als_attrs); if (err < 0) { printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__); goto err_als_sysfs_create_group; } err = stk3x1x_sysfs_create_files(&ps_data->ps_input_dev->dev.kobj, stk_ps_attrs); if (err < 0) { printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__); goto err_ps_sysfs_create_group; } input_set_drvdata(ps_data->als_input_dev, ps_data); input_set_drvdata(ps_data->ps_input_dev, 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(20 * 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); err = stk3x1x_setup_irq(client); if (err < 0) goto err_stk3x1x_setup_irq; #endif device_init_wakeup(&client->dev, true); err = stk3x1x_init_all_setting(client, plat_data); if (err < 0) goto err_init_all_setting; #ifdef CONFIG_HAS_EARLYSUSPEND 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 printk(KERN_INFO "%s: probe successfully\n", __func__); /* added by guoying */ sunxi_gpio_to_name(pin_cfg->gpio, pin_name); /* *printk(KERN_ERR "%s:pin_cfg->mul_sel = %d\n", __func__, pin_cfg->mul_sel); */ if (pin_cfg->pull != GPIO_PULL_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pin_cfg->pull); /*printk(KERN_ERR "%s:pin_cfg->pull = %d\n", __func__, pin_cfg->pull); */ pin_config_set(SUNXI_PINCTRL, pin_name, config); } if (pin_cfg->drv_level != GPIO_DRVLVL_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, pin_cfg->drv_level); pin_config_set(SUNXI_PINCTRL, pin_name, config); } if (pin_cfg->data != GPIO_DATA_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, pin_cfg->data); pin_config_set(SUNXI_PINCTRL, pin_name, config); } /* ended by guoying */ return 0; err_init_all_setting: device_init_wakeup(&client->dev, false); #if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) err_stk3x1x_setup_irq: if (0 != ls_sensor_info.int_number) input_free_int(&(ls_sensor_info.input_type), ps_data); #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); #endif #if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) destroy_workqueue(ps_data->stk_wq); #endif stk3x1x_sysfs_remove_files(&ps_data->ps_input_dev->dev.kobj, stk_ps_attrs); err_ps_sysfs_create_group: stk3x1x_sysfs_remove_files(&ps_data->als_input_dev->dev.kobj, stk_als_attrs); err_als_sysfs_create_group: input_unregister_device(ps_data->ps_input_dev); err_ps_input_register: input_unregister_device(ps_data->als_input_dev); err_als_input_register: input_free_device(ps_data->ps_input_dev); err_ps_input_allocate: input_free_device(ps_data->als_input_dev); err_als_input_allocate: /*support wake lock for ps*/ /*#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)) if (0 != ls_sensor_info.int_number) input_free_int(&(ls_sensor_info.input_type), ps_data); #endif #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&ps_data->stk_early_suspend); #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); #endif #if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) destroy_workqueue(ps_data->stk_wq); #endif stk3x1x_sysfs_remove_files(&ps_data->ps_input_dev->dev.kobj, stk_ps_attrs); stk3x1x_sysfs_remove_files(&ps_data->als_input_dev->dev.kobj, stk_als_attrs); input_unregister_device(ps_data->ps_input_dev); input_unregister_device(ps_data->als_input_dev); /*support wake lock for ps* #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 0; } static const struct i2c_device_id stk_ps_id[] = { { "stk3x1x", 0}, {} }; MODULE_DEVICE_TABLE(i2c, stk_ps_id); static struct i2c_driver stk_ps_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = DEVICE_NAME, .owner = THIS_MODULE, #ifdef CONFIG_PM .suspend = stk3x1x_suspend, .resume = stk3x1x_resume, #endif }, .probe = stk3x1x_probe, .remove = stk3x1x_remove, .id_table = stk_ps_id, .address_list = normal_i2c, }; static int __init stk3x1x_init(void) { int ret = 0; dprintk(DEBUG_INIT, "%s:light sensor driver init\n", __func__); if (input_sensor_startup(&(ls_sensor_info.input_type))) { printk("%s: ls_fetch_sysconfig_para err.\n", __func__); return -1; } else { ret = input_sensor_init(&(ls_sensor_info.input_type)); if (0 != ret) { printk("%s:ls_init_platform_resource err. \n", __func__); } } if (ls_sensor_info.sensor_used == 0) { printk("*** ls_used set to 0 !\n"); printk("*** if use light_sensor,please put the sys_config.fex ls_used set to 1. \n"); return -1; } stk_ps_driver.detect = stk_detect; if (ls_sensor_info.sensor_power_ldo != NULL) { regulator_enable(ls_sensor_info.sensor_power_ldo); msleep(500); } return i2c_add_driver(&stk_ps_driver); } static void __exit stk3x1x_exit(void) { printk("%s exit !!\n", __func__); i2c_del_driver(&stk_ps_driver); input_sensor_free(&(ls_sensor_info.input_type)); } late_initcall(stk3x1x_init); module_exit(stk3x1x_exit); module_param_named(debug_mask, debug_mask, int, 0644); MODULE_AUTHOR("Lex Hsieh "); MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION);