/* * stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x * proximity/ambient light sensor * * Copyright (c) 2013, The Linux Foundation. All Rights Reserved. * Copyright (C) 2012 Lex Hsieh / sensortek or * * * 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. * * Linux Foundation chooses to take subject only to the GPLv2 license * terms, and distributes only under these terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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 #include #ifdef CONFIG_OF #include #endif #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif #include "linux/stk3x1x.h" #define DRIVER_VERSION "3.4.4ts" /* 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 /* #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_PS_INT_MODE = 1 or 4*/ /* 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 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 110000000 #define DEVICE_NAME "stk_ps" #define ALS_NAME "stk3x1x-ls" #define PS_NAME "proximity" /* 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 #define STK_FIR_LEN 16 #define MAX_FIR_LEN 32 static struct sensors_classdev sensors_light_cdev = { .name = "stk3x1x-light", .vendor = "Sensortek", .version = 1, .handle = SENSORS_LIGHT_HANDLE, .type = SENSOR_TYPE_LIGHT, .max_range = "6500", .resolution = "0.0625", .sensor_power = "0.09", .min_delay = (MIN_ALS_POLL_DELAY_NS / 1000), /* us */ .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, .delay_msec = 200, .sensors_enable = NULL, .sensors_poll_delay = NULL, }; static struct sensors_classdev sensors_proximity_cdev = { .name = "stk3x1x-proximity", .vendor = "Sensortek", .version = 1, .handle = SENSORS_PROXIMITY_HANDLE, .type = SENSOR_TYPE_PROXIMITY, .max_range = "5.0", .resolution = "5.0", .sensor_power = "0.1", .min_delay = 0, .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, .delay_msec = 200, .sensors_enable = NULL, .sensors_poll_delay = NULL, }; struct data_filter { u16 raw[MAX_FIR_LEN]; int sum; int number; int idx; }; struct stk3x1x_data { struct i2c_client *client; struct stk3x1x_platform_data *pdata; struct sensors_classdev als_cdev; struct sensors_classdev ps_cdev; #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) int32_t irq; struct work_struct stk_work; struct workqueue_struct *stk_wq; #endif int int_pin; uint8_t wait_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; bool ps_enabled; struct wake_lock ps_wakelock; struct work_struct stk_ps_work; struct workqueue_struct *stk_ps_wq; #ifdef STK_POLL_PS 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; struct hrtimer als_timer; struct hrtimer ps_timer; ktime_t als_poll_delay; ktime_t ps_poll_delay; #ifdef STK_POLL_ALS struct work_struct stk_als_work; struct workqueue_struct *stk_als_wq; #endif struct regulator *vdd; struct regulator *vio; bool power_enabled; bool use_fir; struct data_filter fir; atomic_t firlength; }; #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); 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 int stk3x1x_device_ctl(struct stk3x1x_data *ps_data, bool enable); //static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset); 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; } inline 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;iclient->dev, "alscode[%d]=%d\n", i, alscode); code_threshold_table[i] = (uint16_t)(alscode); } code_threshold_table[i] = 0xffff; dev_dbg(&ps_data->client->dev, "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= (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 int32_t stk3x1x_init_all_reg(struct stk3x1x_data *ps_data, struct stk3x1x_platform_data *plat_data) { int32_t ret; uint8_t w_reg; w_reg = plat_data->state_reg; ret = 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__); return ret; } ps_data->ps_thd_h = plat_data->ps_thd_h; ps_data->ps_thd_l = plat_data->ps_thd_l; w_reg = plat_data->psctrl_reg; ret = i2c_smbus_write_byte_data(ps_data->client, STK_PSCTRL_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } w_reg = plat_data->alsctrl_reg; ret = i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } w_reg = plat_data->ledctrl_reg; ret = i2c_smbus_write_byte_data(ps_data->client, STK_LEDCTRL_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } 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; } w_reg = plat_data->wait_reg; ret = i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h); stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l); 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 ret = i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, w_reg); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } ret = i2c_smbus_write_byte_data(ps_data->client, 0x87, 0x60); if (ret < 0) { dev_err(&ps_data->client->dev, "%s: write i2c error\n", __func__); return ret; } return 0; } static int32_t stk3x1x_check_pid(struct stk3x1x_data *ps_data) { int32_t err1, err2; err1 = i2c_smbus_read_byte_data(ps_data->client,STK_PDT_ID_REG); if (err1 < 0) { printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err1); return err1; } err2 = i2c_smbus_read_byte_data(ps_data->client,STK_RSRVD_REG); if (err2 < 0) { printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err2); return -1; } if(err2 == 0xC0) printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__); return 0; } static int32_t stk3x1x_software_reset(struct stk3x1x_data *ps_data) { int32_t r; uint8_t w_reg; w_reg = 0x7F; r = 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 = 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 = 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) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&thd_l; temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_ALS_REG,thd_l); } static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&thd_h; temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_ALS_REG,thd_h); } static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&thd_l; temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; ps_data->ps_thd_l = thd_l; return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_PS_REG,thd_l); } static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&thd_h; temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; ps_data->ps_thd_h = thd_h; return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_PS_REG,thd_h); } /* static int32_t stk3x1x_set_ps_foffset(struct stk3x1x_data *ps_data, uint16_t offset) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&offset; temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; return i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset); } static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset) { uint8_t temp; uint8_t* pSrc = (uint8_t*)&offset; int ret; uint8_t w_state_reg; uint8_t re_en; ret = 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; } re_en = (ret & STK_STATE_EN_AK_MASK) ? 1: 0; if(re_en) { w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_AK_MASK)); ret = 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; } msleep(1); } temp = *pSrc; *pSrc = *(pSrc+1); *(pSrc+1) = temp; ret = i2c_smbus_write_word_data(ps_data->client,0x0E,offset); if(!re_en) return ret; w_state_reg |= STK_STATE_EN_AK_MASK; ret = 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 0; } */ static inline uint32_t stk3x1x_get_ps_reading(struct stk3x1x_data *ps_data) { int32_t word_data, tmp_word_data; tmp_word_data = i2c_smbus_read_word_data(ps_data->client,STK_DATA1_PS_REG); if(tmp_word_data < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data); return tmp_word_data; } word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ; return word_data; } static int32_t stk3x1x_set_flag(struct stk3x1x_data *ps_data, uint8_t org_flag_reg, uint8_t clr) { uint8_t w_flag; 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); return i2c_smbus_write_byte_data(ps_data->client,STK_FLAG_REG, w_flag); } static int32_t stk3x1x_get_flag(struct stk3x1x_data *ps_data) { return i2c_smbus_read_byte_data(ps_data->client,STK_FLAG_REG); } static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable) { int32_t ret; uint8_t w_state_reg; uint8_t curr_ps_enable; curr_ps_enable = ps_data->ps_enabled?1:0; if(curr_ps_enable == enable) return 0; if (enable) { ret = stk3x1x_device_ctl(ps_data, enable); if (ret) return ret; } ret = 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 | 0x60); if(enable) { w_state_reg |= STK_STATE_EN_PS_MASK; if(!(ps_data->als_enabled)) w_state_reg |= STK_STATE_EN_WAIT_MASK; } ret = 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) { #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 ps_data->ps_enabled = true; #ifndef STK_POLL_PS #ifndef STK_POLL_ALS if(!(ps_data->als_enabled)) #endif /* #ifndef STK_POLL_ALS */ enable_irq(ps_data->irq); msleep(1); ret = stk3x1x_get_flag(ps_data); if (ret < 0) { printk(KERN_ERR "%s: read i2c error, ret=%d\n", __func__, ret); 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); dev_dbg(&ps_data->client->dev, "%s: ps input event=%d, ps code = %d\n", __func__, near_far_state, reading); #endif /* #ifndef STK_POLL_PS */ } else { #ifdef STK_POLL_PS hrtimer_cancel(&ps_data->ps_timer); #else #ifndef STK_POLL_ALS if(!(ps_data->als_enabled)) #endif disable_irq(ps_data->irq); #endif ps_data->ps_enabled = false; } if (!enable) { ret = stk3x1x_device_ctl(ps_data, enable); if (ret) return ret; } 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; if(curr_als_enable == enable) return 0; if (enable) { ret = stk3x1x_device_ctl(ps_data, enable); if (ret) return ret; } #ifndef STK_POLL_ALS if (enable) { stk3x1x_set_als_thd_h(ps_data, 0x0000); stk3x1x_set_als_thd_l(ps_data, 0xFFFF); } #endif ret = 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 = 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); #else #ifndef STK_POLL_PS if(!(ps_data->ps_enabled)) #endif disable_irq(ps_data->irq); #endif } if (!enable) { ret = stk3x1x_device_ctl(ps_data, enable); if (ret) return ret; } return ret; } static inline int32_t stk3x1x_filter_reading(struct stk3x1x_data *ps_data, int32_t word_data) { int index; int firlen = atomic_read(&ps_data->firlength); 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; } return word_data; } static inline int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data) { int32_t word_data, tmp_word_data; tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_ALS_REG); if(tmp_word_data < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data); return tmp_word_data; } word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ; if (ps_data->use_fir) word_data = stk3x1x_filter_reading(ps_data, word_data); return word_data; } static int32_t stk3x1x_get_ir_reading(struct stk3x1x_data *ps_data) { int32_t word_data, tmp_word_data; int32_t ret; uint8_t w_reg, retry = 0; if(ps_data->ps_enabled) { stk3x1x_enable_ps(ps_data, 0); ps_data->ps_enabled = true; } ret = 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_reg = (uint8_t)(ret & (~STK_STATE_EN_IRS_MASK)); w_reg |= STK_STATE_EN_IRS_MASK; ret = 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__); return ret; } msleep(100); do { msleep(50); ret = stk3x1x_get_flag(ps_data); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } retry++; }while(retry < 5 && ((ret&STK_FLG_IR_RDY_MASK) == 0)); if(retry == 5) { printk(KERN_ERR "%s: ir data is not ready for 300ms\n", __func__); return -EINVAL; } ret = stk3x1x_get_flag(ps_data); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } ret = stk3x1x_set_flag(ps_data, ret, STK_FLG_IR_RDY_MASK); if (ret < 0) { printk(KERN_ERR "%s: write i2c error\n", __func__); return ret; } tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_IR_REG); if(tmp_word_data < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data); return tmp_word_data; } word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ; if(ps_data->ps_enabled) stk3x1x_enable_ps(ps_data, 1); return word_data; } 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 int stk_als_enable_set(struct sensors_classdev *sensors_cdev, unsigned int enabled) { struct stk3x1x_data *als_data = container_of(sensors_cdev, struct stk3x1x_data, als_cdev); int err; mutex_lock(&als_data->io_lock); err = stk3x1x_enable_als(als_data, enabled); mutex_unlock(&als_data->io_lock); if (err < 0) return err; return 0; } 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 = 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; } dev_dbg(dev, "%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); mutex_lock(&ps_data->io_lock); als_lux = stk_alscode2lux(ps_data, als_reading); mutex_unlock(&ps_data->io_lock); 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; } mutex_lock(&ps_data->io_lock); ps_data->als_lux_last = value; input_report_abs(ps_data->als_input_dev, ABS_MISC, value); input_sync(ps_data->als_input_dev); mutex_unlock(&ps_data->io_lock); dev_dbg(dev, "%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; mutex_lock(&ps_data->io_lock); transmittance = ps_data->als_transmittance; mutex_unlock(&ps_data->io_lock); 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; } mutex_lock(&ps_data->io_lock); ps_data->als_transmittance = value; mutex_unlock(&ps_data->io_lock); 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); return scnprintf(buf, PAGE_SIZE, "%u\n", (u32)ktime_to_ms(ps_data->als_poll_delay)); } static inline void stk_als_delay_store_fir(struct stk3x1x_data *ps_data) { ps_data->fir.number = 0; ps_data->fir.idx = 0; ps_data->fir.sum = 0; } static int stk_als_poll_delay_set(struct sensors_classdev *sensors_cdev, unsigned int delay_msec) { struct stk3x1x_data *als_data = container_of(sensors_cdev, struct stk3x1x_data, als_cdev); uint64_t value = 0; value = delay_msec * 1000000; if (value < MIN_ALS_POLL_DELAY_NS) value = MIN_ALS_POLL_DELAY_NS; mutex_lock(&als_data->io_lock); if (value != ktime_to_ns(als_data->als_poll_delay)) als_data->als_poll_delay = ns_to_ktime(value); if (als_data->use_fir) stk_als_delay_store_fir(als_data); mutex_unlock(&als_data->io_lock); return 0; } 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 *als_data = dev_get_drvdata(dev); ret = kstrtoull(buf, 10, &value); if(ret < 0) { dev_err(dev, "%s:kstrtoull failed, ret=0x%x\n", __func__, ret); return ret; } #ifdef STK_DEBUG_PRINTF dev_dbg(dev, "%s: set als poll delay=%lld\n", __func__, value); #endif ret = stk_als_poll_delay_set(&als_data->als_cdev, value); if (ret < 0) return ret; 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); } 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); dev_dbg(dev, "%s: len = %2d, idx = %2d\n", __func__, len, ps_data->fir.idx); dev_dbg(dev, "%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) { dev_err(dev, "%s:strict_strtoull failed, ret=0x%x\n", __func__, ret); return ret; } if (value > MAX_FIR_LEN) { dev_err(dev, "%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; } static ssize_t stk_als_fir_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->use_fir); } static ssize_t stk_als_fir_enable_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) { dev_err(dev, "%s:strict_strtoull failed, ret=0x%x\n", __func__, ret); return ret; } if (value) { ps_data->use_fir = true; memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); } else { ps_data->use_fir = false; } return size; } 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 int stk_ps_enable_set(struct sensors_classdev *sensors_cdev, unsigned int enabled) { struct stk3x1x_data *ps_data = container_of(sensors_cdev, struct stk3x1x_data, ps_cdev); int err; mutex_lock(&ps_data->io_lock); err = stk3x1x_enable_ps(ps_data, enabled); mutex_unlock(&ps_data->io_lock); if (err < 0) return err; return 0; } 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 = 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; } dev_dbg(dev, "%s: Enable PS : %d\n", __func__, en); mutex_lock(&ps_data->io_lock); stk3x1x_enable_ps(ps_data, en); 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 = 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; } dev_dbg(dev, "%s: Enable PS ASO : %d\n", __func__, en); ret = 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 = 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, tmp_word_data; tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_OFFSET_REG); if(tmp_word_data < 0) { printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data); return tmp_word_data; } word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ; 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 value = 0; int ret; uint16_t offset; ret = kstrtoul(buf, 10, &value); if(ret < 0) { printk(KERN_ERR "%s:kstrtoul failed, ret=0x%x\n", __func__, ret); return ret; } if(value > 65535) { printk(KERN_ERR "%s: invalid value, offset=%ld\n", __func__, value); return -EINVAL; } offset = (uint16_t) ((value&0x00FF) << 8) | ((value&0xFF00) >>8); ret = i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset); 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; mutex_lock(&ps_data->io_lock); ret = stk3x1x_get_flag(ps_data); if(ret < 0) { printk(KERN_ERR "%s: stk3x1x_get_flag failed, ret=0x%x\n", __func__, ret); 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); mutex_unlock(&ps_data->io_lock); wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); dev_dbg(dev, "%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; } mutex_lock(&ps_data->io_lock); ps_data->ps_distance_last = value; input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, value); input_sync(ps_data->ps_input_dev); mutex_unlock(&ps_data->io_lock); wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ); dev_dbg(dev, "%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); mutex_lock(&ps_data->io_lock); ps_thd_l1_reg = 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 = 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; } mutex_unlock(&ps_data->io_lock); 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; } mutex_lock(&ps_data->io_lock); stk3x1x_set_ps_thd_l(ps_data, value); mutex_unlock(&ps_data->io_lock); 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); mutex_lock(&ps_data->io_lock); ps_thd_h1_reg = 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 = 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; } mutex_unlock(&ps_data->io_lock); 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; } mutex_lock(&ps_data->io_lock); stk3x1x_set_ps_thd_h(ps_data, value); mutex_unlock(&ps_data->io_lock); 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; mutex_lock(&ps_data->io_lock); als_thd_l0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_ALS_REG); als_thd_l1_reg = 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); mutex_unlock(&ps_data->io_lock); 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; } mutex_lock(&ps_data->io_lock); value = stk_lux2alscode(ps_data, value); stk3x1x_set_als_thd_l(ps_data, value); mutex_unlock(&ps_data->io_lock); 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; mutex_lock(&ps_data->io_lock); als_thd_h0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_ALS_REG); als_thd_h1_reg = 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); mutex_unlock(&ps_data->io_lock); 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 = strict_strtoul(buf, 10, &value); if(ret < 0) { printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret); return ret; } mutex_lock(&ps_data->io_lock); value = stk_lux2alscode(ps_data, value); stk3x1x_set_als_thd_h(ps_data, value); mutex_unlock(&ps_data->io_lock); return size; } #endif static ssize_t stk_all_reg_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); mutex_lock(&ps_data->io_lock); for(cnt=0;cnt<25;cnt++) { ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, (cnt)); if(ps_reg[cnt] < 0) { mutex_unlock(&ps_data->io_lock); printk(KERN_ERR "stk_all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]); return -EINVAL; } else { dev_dbg(dev, "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]); } } ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG); if(ps_reg[cnt] < 0) { mutex_unlock(&ps_data->io_lock); printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]); return -EINVAL; } dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]); cnt++; ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG); if(ps_reg[cnt] < 0) { mutex_unlock(&ps_data->io_lock); printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]); return -EINVAL; } dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]); mutex_unlock(&ps_data->io_lock); return scnprintf(buf, PAGE_SIZE, "%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %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_recv_show(struct device *dev, struct device_attribute *attr, char *buf) { return 0; } 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 = i2c_smbus_read_byte_data(ps_data->client,value); printk("%s: reg 0x%x=0x%x\n", __func__, (int)value, 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; u8 addr_u8, cmd_u8; 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; } dev_dbg(dev, "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd); addr_u8 = (u8) addr; cmd_u8 = (u8) cmd; //mutex_lock(&ps_data->io_lock); ret = i2c_smbus_write_byte_data(ps_data->client,addr_u8,cmd_u8); //mutex_unlock(&ps_data->io_lock); if (0 != ret) { printk(KERN_ERR "%s: i2c_smbus_write_byte_data fail\n", __func__); return ret; } return size; } static struct device_attribute als_enable_attribute = __ATTR(enable,0664,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(poll_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); static struct device_attribute als_firlen_attribute = __ATTR(firlen, 0664, stk_als_firlen_show, stk_als_firlen_store); static struct device_attribute als_fir_enable_attribute = __ATTR(fir_enable, 0664, stk_als_fir_enable_show, stk_als_fir_enable_store); 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, &als_firlen_attribute.attr, &als_fir_enable_attribute.attr, NULL }; static struct attribute_group stk_als_attribute_group = { .attrs = stk_als_attrs, }; static struct device_attribute ps_enable_attribute = __ATTR(enable,0664,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 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 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, &recv_attribute.attr, &send_attribute.attr, &all_reg_attribute.attr, NULL }; static struct attribute_group stk_ps_attribute_group = { .attrs = stk_ps_attrs, }; #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_work_func(struct work_struct *work) { struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_als_work); int32_t reading; mutex_lock(&ps_data->io_lock); reading = stk3x1x_get_als_reading(ps_data); if(reading < 0) return; 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); mutex_unlock(&ps_data->io_lock); } #endif 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); #ifdef STK_POLL_PS hrtimer_forward_now(&ps_data->ps_timer, ps_data->ps_poll_delay); return HRTIMER_RESTART; #else hrtimer_cancel(&ps_data->ps_timer); return HRTIMER_NORESTART; #endif } static void stk_ps_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; mutex_lock(&ps_data->io_lock); org_flag_reg = stk3x1x_get_flag(ps_data); if(org_flag_reg < 0) { printk(KERN_ERR "%s: get_status_reg fail, ret=%d", __func__, org_flag_reg); goto err_i2c_rw; } 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) { printk(KERN_ERR "%s:stk3x1x_set_flag fail, ret=%d\n", __func__, ret); goto err_i2c_rw; } mutex_unlock(&ps_data->io_lock); return; err_i2c_rw: mutex_unlock(&ps_data->io_lock); msleep(30); return; } #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; #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; mutex_lock(&ps_data->io_lock); #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) { printk(KERN_ERR "%s: get_status_reg fail, org_flag_reg=%d", __func__, org_flag_reg); 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 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 } ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag); if(ret < 0) { printk(KERN_ERR "%s:reset_int_flag fail, ret=%d\n", __func__, ret); goto err_i2c_rw; } #endif msleep(1); enable_irq(ps_data->irq); mutex_unlock(&ps_data->io_lock); return; err_i2c_rw: mutex_unlock(&ps_data->io_lock); msleep(30); enable_irq(ps_data->irq); return; } #endif #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) 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)) */ static inline void stk3x1x_init_fir(struct stk3x1x_data *ps_data) { memset(&ps_data->fir, 0x00, sizeof(ps_data->fir)); atomic_set(&ps_data->firlength, STK_FIR_LEN); } 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; stk3x1x_check_pid(ps_data); if(ret < 0) return ret; ret = stk3x1x_init_all_reg(ps_data, plat_data); if(ret < 0) return ret; #ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD stk_init_code_threshold_table(ps_data); #endif if (plat_data->use_fir) stk3x1x_init_fir(ps_data); 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); irq = gpio_to_irq(ps_data->int_pin); #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, 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: gpio_free(ps_data->int_pin); return err; } #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); #ifndef STK_POLL_PS int err; #endif mutex_lock(&ps_data->io_lock); if(ps_data->als_enabled) { stk3x1x_enable_als(ps_data, 0); ps_data->als_enabled = true; } if(ps_data->ps_enabled) { #ifdef STK_POLL_PS wake_lock(&ps_data->ps_nosuspend_wl); #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 mutex_lock(&ps_data->io_lock); if(ps_data->als_enabled) stk3x1x_enable_als(ps_data, 1); if(ps_data->ps_enabled) { #ifdef STK_POLL_PS wake_lock(&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 } mutex_unlock(&ps_data->io_lock); return; } #endif //#ifdef CONFIG_HAS_EARLYSUSPEND 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); ret = regulator_enable(data->vdd); if (ret) { dev_err(&data->client->dev, "Regulator vdd enable failed ret=%d\n", ret); } return ret; } data->power_enabled = on; 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; 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) { if (!ps_data->als_enabled && !ps_data->ps_enabled) { 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; } #ifdef CONFIG_OF static int stk3x1x_parse_dt(struct device *dev, struct stk3x1x_platform_data *pdata) { 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"); return 0; } #else static int stk3x1x_parse_dt(struct device *dev, struct stk3x1x_platform_data *pdata) { return -ENODEV; } #endif /* !CONFIG_OF */ 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_SMBUS_BYTE_DATA)) { printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_BYTE_DATA\n", __func__); return -ENODEV; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_WORD_DATA\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) { 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); dev_err(&client->dev, "%s: stk3x1x_parse_dt ret=%d\n", __func__, err); if (err) return err; } else plat_data = client->dev.platform_data; 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->use_fir = plat_data->use_fir; 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; } ps_data->als_input_dev = devm_input_allocate_device(&client->dev); 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 = devm_input_allocate_device(&client->dev); if (ps_data->ps_input_dev==NULL) { printk(KERN_ERR "%s: could not allocate ps device\n", __func__); err = -ENOMEM; goto err_als_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); 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_allocate; } 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_als_input_allocate; } 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__); goto err_als_input_allocate; } 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__); 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_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 ps_data->stk_ps_wq = create_singlethread_workqueue("stk_ps_wq"); INIT_WORK(&ps_data->stk_ps_work, stk_ps_work_func); hrtimer_init(&ps_data->ps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ps_data->ps_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC); ps_data->ps_timer.function = stk_ps_timer_func; #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 err = stk3x1x_power_init(ps_data, true); if (err) goto err_power_init; err = stk3x1x_power_ctl(ps_data, true); if (err) goto err_power_on; ps_data->als_enabled = false; ps_data->ps_enabled = false; #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 /* make sure everything is ok before registering the class device */ ps_data->als_cdev = sensors_light_cdev; ps_data->als_cdev.sensors_enable = stk_als_enable_set; ps_data->als_cdev.sensors_poll_delay = stk_als_poll_delay_set; err = sensors_classdev_register(&client->dev, &ps_data->als_cdev); if (err) goto err_power_on; ps_data->ps_cdev = sensors_proximity_cdev; ps_data->ps_cdev.sensors_enable = stk_ps_enable_set; err = sensors_classdev_register(&client->dev, &ps_data->ps_cdev); if (err) goto err_class_sysfs; /* enable device power only when it is enabled */ err = stk3x1x_power_ctl(ps_data, false); if (err) goto err_init_all_setting; dev_dbg(&client->dev, "%s: probe successfully", __func__); return 0; err_init_all_setting: stk3x1x_power_ctl(ps_data, false); sensors_classdev_unregister(&ps_data->ps_cdev); err_class_sysfs: sensors_classdev_unregister(&ps_data->als_cdev); err_power_on: stk3x1x_power_init(ps_data, false); err_power_init: #ifndef STK_POLL_PS free_irq(ps_data->irq, ps_data); gpio_free(plat_data->int_pin); #endif #if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS)) err_stk3x1x_setup_irq: #endif #ifdef STK_POLL_ALS hrtimer_try_to_cancel(&ps_data->als_timer); destroy_workqueue(ps_data->stk_als_wq); #endif destroy_workqueue(ps_data->stk_ps_wq); #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); err_ps_sysfs_create_group: sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group); 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); #ifndef STK_POLL_PS free_irq(ps_data->irq, ps_data); gpio_free(ps_data->int_pin); #endif #ifdef STK_POLL_ALS hrtimer_try_to_cancel(&ps_data->als_timer); destroy_workqueue(ps_data->stk_als_wq); #endif destroy_workqueue(ps_data->stk_ps_wq); #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); #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[] = { { "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, .of_match_table = stk_match_table, }, .probe = stk3x1x_probe, .remove = stk3x1x_remove, .id_table = stk_ps_id, }; static int __init stk3x1x_init(void) { int ret; ret = i2c_add_driver(&stk_ps_driver); if (ret) 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);