From 871480933a1c28f8a9fed4c4d34d06c439a7a422 Mon Sep 17 00:00:00 2001 From: Srikant Patnaik Date: Sun, 11 Jan 2015 12:28:04 +0530 Subject: Moved, renamed, and deleted files The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure. --- drivers/input/sensor/isl29023_lsensor/Makefile | 34 + drivers/input/sensor/isl29023_lsensor/isl29023.c | 1164 ++++++++++++++++++++++ 2 files changed, 1198 insertions(+) create mode 100755 drivers/input/sensor/isl29023_lsensor/Makefile create mode 100755 drivers/input/sensor/isl29023_lsensor/isl29023.c (limited to 'drivers/input/sensor/isl29023_lsensor') diff --git a/drivers/input/sensor/isl29023_lsensor/Makefile b/drivers/input/sensor/isl29023_lsensor/Makefile new file mode 100755 index 00000000..ac959091 --- /dev/null +++ b/drivers/input/sensor/isl29023_lsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_isl29023 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := isl29023.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/drivers/input/sensor/isl29023_lsensor/isl29023.c b/drivers/input/sensor/isl29023_lsensor/isl29023.c new file mode 100755 index 00000000..3366e92a --- /dev/null +++ b/drivers/input/sensor/isl29023_lsensor/isl29023.c @@ -0,0 +1,1164 @@ +/* + * isl29023.c - Intersil ISL29023 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "../sensor.h" + +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(isl29023); + +#define MODULE_NAME "isl29023" + +#define SENSOR_I2C_NAME "isl29023" +#define SENSOR_I2C_ADDR 0x44 + +#undef dbg +#define dbg(fmt, args...) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +/* ICS932S401 registers */ +#define ISL29023_REG_VENDOR_REV 0x06 +#define ISL29023_VENDOR 1 +#define ISL29023_VENDOR_MASK 0x0F +#define ISL29023_REV 4 +#define ISL29023_REV_SHIFT 4 +#define ISL29023_REG_DEVICE 0x44 +#define ISL29023_DEVICE 44 + + +#define REG_CMD_1 0x00 +#define REG_CMD_2 0x01 +#define REG_DATA_LSB 0x02 +#define REG_DATA_MSB 0x03 +#define ISL_MOD_MASK 0xE0 +#define ISL_MOD_POWERDOWN 0 +#define ISL_MOD_ALS_ONCE 1 +#define ISL_MOD_IR_ONCE 2 +#define ISL_MOD_RESERVED 4 +#define ISL_MOD_ALS_CONT 5 +#define ISL_MOD_IR_CONT 6 +#define IR_CURRENT_MASK 0xC0 +#define IR_FREQ_MASK 0x30 +#define SENSOR_RANGE_MASK 0x03 +#define ISL_RES_MASK 0x0C + +static int last_mod; + +static struct i2c_client *this_client = NULL; +struct isl_device { + struct input_polled_dev* input_poll_dev; + struct i2c_client* client; + int resolution; + int range; + int isdbg; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct isl_device* l_sensorconfig = NULL; +static struct kobject *android_lsensor_kobj = NULL; +static int l_enable = 1; // 0:don't report data + +static DEFINE_MUTEX(mutex); + +static int isl_set_range(struct i2c_client *client, int range) +{ + int ret_val; + + ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (ret_val < 0) + return -EINVAL; + ret_val &= ~SENSOR_RANGE_MASK; /*reset the bit */ + ret_val |= range; + ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 set_range call, \n", __func__); + if (ret_val < 0) + return ret_val; + return range; +} + +static int isl_set_mod(struct i2c_client *client, int mod) +{ + int ret, val, freq; + + switch (mod) { + case ISL_MOD_POWERDOWN: + case ISL_MOD_RESERVED: + goto setmod; + case ISL_MOD_ALS_ONCE: + case ISL_MOD_ALS_CONT: + freq = 0; + break; + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + freq = 1; + break; + default: + return -EINVAL; + } + /* set IR frequency */ + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (val < 0) + return -EINVAL; + val &= ~IR_FREQ_MASK; + if (freq) + val |= IR_FREQ_MASK; + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (ret < 0) + return -EINVAL; + +setmod: + /* set operation mod */ + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + val &= ~ISL_MOD_MASK; + val |= (mod << 5); + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, val); + if (ret < 0) + return -EINVAL; + + if (mod != ISL_MOD_POWERDOWN) + last_mod = mod; + + return mod; +} + +static int isl_get_res(struct i2c_client *client) +{ + int val; + + printk(KERN_INFO MODULE_NAME ": %s isl29023 get_res call, \n", __func__); + val = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + + if (val < 0) + return -EINVAL; + + val &= ISL_RES_MASK; + val >>= 2; + + switch (val) { + case 0: + return 65536; + case 1: + return 4096; + case 2: + return 256; + case 3: + return 16; + default: + return -EINVAL; + } +} + +static int isl_get_mod(struct i2c_client *client) +{ + int val; + + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + return val >> 5; +} + +static int isl_get_range(struct i2c_client* client) +{ + switch (i2c_smbus_read_word_data(client, 0)>>8 & 0xff & 0x3) { + case 0: return 1000; + case 1: return 4000; + case 2: return 16000; + case 3: return 64000; + default: return -EINVAL; + } +} + +static ssize_t +isl_sensing_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int val; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + dev_dbg(dev, "%s: range: 0x%.2x\n", __func__, val); + + if (val < 0) + return val; + return sprintf(buf, "%d000\n", 1 << (2 * (val & 3))); +} + +static ssize_t +ir_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int val; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + dev_dbg(dev, "%s: IR current: 0x%.2x\n", __func__, val); + + if (val < 0) + return -EINVAL; + val >>= 6; + + switch (val) { + case 0: + val = 100; + break; + case 1: + val = 50; + break; + case 2: + val = 25; + break; + case 3: + val = 0; + break; + default: + return -EINVAL; + } + + if (val) + val = sprintf(buf, "%d\n", val); + else + val = sprintf(buf, "%s\n", "12.5"); + return val; +} + +static ssize_t +isl_sensing_mod_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +// struct i2c_client *client = to_i2c_client(dev); + + dev_dbg(dev, "%s: mod: 0x%.2x\n", __func__, last_mod); + + switch (last_mod) { + case ISL_MOD_POWERDOWN: + return sprintf(buf, "%s\n", "0-Power-down"); + case ISL_MOD_ALS_ONCE: + return sprintf(buf, "%s\n", "1-ALS once"); + case ISL_MOD_IR_ONCE: + return sprintf(buf, "%s\n", "2-IR once"); + case ISL_MOD_RESERVED: + return sprintf(buf, "%s\n", "4-Reserved"); + case ISL_MOD_ALS_CONT: + return sprintf(buf, "%s\n", "5-ALS continuous"); + case ISL_MOD_IR_CONT: + return sprintf(buf, "%s\n", "6-IR continuous"); + default: + return -EINVAL; + } +} + +static ssize_t +isl_output_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret_val, mod; + unsigned long int output = 0; + int temp; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + + temp = i2c_smbus_read_byte_data(client, REG_DATA_MSB); + if (temp < 0) + goto err_exit; + ret_val = i2c_smbus_read_byte_data(client, REG_DATA_LSB); + if (ret_val < 0) + goto err_exit; + ret_val |= temp << 8; + + dev_dbg(dev, "%s: Data: %04x\n", __func__, ret_val); + + mod = isl_get_mod(client); + switch (last_mod) { + case ISL_MOD_ALS_CONT: + case ISL_MOD_ALS_ONCE: + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + output = ret_val; + break; + default: + goto err_exit; + } + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return sprintf(buf, "%ld\n", output); + +err_exit: + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return -EINVAL; +} + +static int isl_get_lux_data(struct i2c_client* client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + __u16 resH, resL; + //int range; + resL = i2c_smbus_read_word_data(client, 1)>>8; + resH = i2c_smbus_read_word_data(client, 2)&0xff00; + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + return (resH | resL) * idev->range / idev->resolution; +} +static ssize_t +isl_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + __u16 resH, resL;// L1, L2, H1, H2, thresL, thresH; + char cmd2; + int res, data, tmp, range, resolution; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + +// cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; // 01h + resL = i2c_smbus_read_word_data(client, 1)>>8; // 02h + resH = i2c_smbus_read_word_data(client, 2)&0xff00; // 03h +// L1 = i2c_smbus_read_word_data(client, 3)>>8; // 04h +// L2 = i2c_smbus_read_word_data(client, 4)&0xff00; // 05h +// H1 = i2c_smbus_read_word_data(client, 5)>>8; // 06h +// H2 = i2c_smbus_read_word_data(client, 6)&0xff00; // 07h + + res = resH | resL; +// thresL = L2 | L1; +// thresH = H2 | H1; + + cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + resolution = isl_get_res(client); //resolution + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + tmp = cmd2 & 0x3; //range + switch (tmp) { + case 0: + range = 1000; + break; + case 1: + range = 4000; + break; + case 2: + range = 16000; + break; + case 3: + range = 64000; + break; + default: + return -EINVAL; + } + data = res * range / resolution; + +// printk("Data = 0x%04x [%d]\n", data, data); +// printk("CMD2 = 0x%x\n", cmd2); +// printk("Threshold Low = 0x%04x\n", thresL); +// printk("Threshold High = 0x%04x\n", thresH); + + return sprintf(buf, "%u\n", data); +} + +static ssize_t +isl_cmd2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long cmd2; + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg(" cmd2: 0x%02x\n", cmd2); + switch (cmd2) { + case 0: + return sprintf(buf, "%s\n", "[cmd2 = 0] n = 16, range = 1000"); + case 1: + return sprintf(buf, "%s\n", "[cmd2 = 1] n = 16, range = 4000"); + case 2: + return sprintf(buf, "%s\n", "[cmd2 = 2] n = 16, range = 16000"); + case 3: + return sprintf(buf, "%s\n", "[cmd2 = 3] n = 16, range = 64000"); + + case 4: + return sprintf(buf, "%s\n", "[cmd2 = 4] n = 12, range = 1000"); + case 5: + return sprintf(buf, "%s\n", "[cmd2 = 5] n = 12, range = 4000"); + case 6: + return sprintf(buf, "%s\n", "[cmd2 = 6] n = 12, range = 16000"); + case 7: + return sprintf(buf, "%s\n", "[cmd2 = 7] n = 12, range = 64000"); + + case 8: + return sprintf(buf, "%s\n", "[cmd2 = 8] n = 8, range = 1000"); + case 9: + return sprintf(buf, "%s\n", "[cmd2 = 9] n = 8, range = 4000"); + case 10: + return sprintf(buf, "%s\n", "[cmd2 = 10] n = 8, range = 16000"); + case 11: + return sprintf(buf, "%s\n", "[cmd2 = 11] n = 8, range = 64000"); + + case 12: + return sprintf(buf, "%s\n", "[cmd2 = 12] n = 4, range = 1000"); + case 13: + return sprintf(buf, "%s\n", "[cmd2 = 13] n = 4, range = 4000"); + case 14: + return sprintf(buf, "%s\n", "[cmd2 = 14] n = 4, range = 16000"); + case 15: + return sprintf(buf, "%s\n", "[cmd2 = 15] n = 4, range = 64000"); + + default: + return -EINVAL; + } +} + + +static ssize_t +isl_sensing_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned int ret_val; + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + switch (val) { + case 1000: + val = 0; + break; + case 4000: + val = 1; + break; + case 16000: + val = 2; + break; + case 64000: + val = 3; + break; + default: + return -EINVAL; + } + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + ret_val = isl_set_range(client, val); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + if (ret_val < 0) + return ret_val; + return count; +} + +static ssize_t +ir_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned int ret_val; + unsigned long val; + + if (!strncmp(buf, "12.5", 4)) + val = 3; + else { + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + switch (val) { + case 100: + val = 0; + break; + case 50: + val = 1; + break; + case 25: + val = 2; + break; + default: + return -EINVAL; + } + } + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + + ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (ret_val < 0) + goto err_exit; + + ret_val &= ~IR_CURRENT_MASK; /*reset the bit before setting them */ + ret_val |= (val << 6); + + ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val); + if (ret_val < 0) + goto err_exit; + + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + return count; + +err_exit: + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + return -EINVAL; +} + +static ssize_t +isl_sensing_mod_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret_val; + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + if (val > 7) + return -EINVAL; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + ret_val = isl_set_mod(client, val); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + if (ret_val < 0) + return ret_val; + return count; +} + +static ssize_t +isl_cmd2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct isl_device* idev = i2c_get_clientdata(client); + int res; + unsigned long val; + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + if (val > 15 || val < 0) + return -EINVAL; + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + res = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (res < 0) + printk("Warning - write failed\n"); + + idev->resolution = isl_get_res(client); + idev->range = isl_get_range(client); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + return count; +} + +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, + isl_sensing_range_show, isl_sensing_range_store); +static DEVICE_ATTR(mod, S_IRUGO | S_IWUSR, + isl_sensing_mod_show, isl_sensing_mod_store); +static DEVICE_ATTR(ir_current, S_IRUGO | S_IWUSR, + ir_current_show, ir_current_store); +static DEVICE_ATTR(output, S_IRUGO, isl_output_data_show, NULL); +static DEVICE_ATTR(cmd2, S_IRUGO | S_IWUSR, + isl_cmd2_show, isl_cmd2_store); +static DEVICE_ATTR(lux, S_IRUGO, + isl_lux_show, NULL); + +static struct attribute *mid_att_isl[] = { + &dev_attr_range.attr, + &dev_attr_mod.attr, + &dev_attr_ir_current.attr, + &dev_attr_output.attr, + &dev_attr_lux.attr, + &dev_attr_cmd2.attr, + NULL +}; + +static struct attribute_group m_isl_gr = { + .name = "isl29023", + .attrs = mid_att_isl +}; + +static int isl_set_default_config(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + int ret=0; +/* We don't know what it does ... */ +// ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xE0); +// ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0xC3); +/* Set default to ALS continuous */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xA0); + if (ret < 0) + return -EINVAL; +/* Range: 0~16000, number of clock cycles: 65536 */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0x02); // vivienne + if (ret < 0) + return -EINVAL; + idev->resolution = isl_get_res(client); + idev->range = isl_get_range(client);; + dbg("isl29023 set_default_config call, \n"); + + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int isl29023_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + struct i2c_adapter *adapter = client->adapter; + int vendor, device, revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + //printk(KERN_INFO MODULE_NAME ": %s isl29023 detact call, kind:%d type:%s addr:%x \n", __func__, kind, info->type, info->addr); + + /* if (kind <= 0)*/ { + + + vendor = i2c_smbus_read_word_data(client, + ISL29023_REG_VENDOR_REV); + dbg("read vendor=%d(0x%x)\n", vendor,vendor); + if (0x0FFFF == vendor) + { + dbg("find isl29023!\n"); + return 0; + } else { + return -ENODEV; + } + vendor >>= 8; + revision = vendor >> ISL29023_REV_SHIFT; + vendor &= ISL29023_VENDOR_MASK; + if (vendor != ISL29023_VENDOR) + { + dbg("real_vendor=0x%x,tvendor=0x%x\n",vendor,ISL29023_VENDOR); + return -ENODEV; + } + + device = i2c_smbus_read_word_data(client, + ISL29023_REG_DEVICE); + dbg("device=%x\n", device); + device >>= 8; + if (device != ISL29023_DEVICE) + { + dbg("real_device=0x%x, tdevice=0x%x\n", device, ISL29023_DEVICE); + return -ENODEV; + } + + if (revision != ISL29023_REV) + { + dbg("Unknown revision %d\n", + revision); + } + } /*else + dev_dbg(&adapter->dev, "detection forced\n");*/ + + // strlcpy(info->type, "isl29023", I2C_NAME_SIZE); + + return 0; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll(struct input_polled_dev *dev) +{ + struct isl_device* idev = dev->private; + struct input_dev* input = idev->input_poll_dev->input; + struct i2c_client* client = idev->client; + + if (l_enable != 0) + { + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + input_report_abs(input, ABS_MISC, isl_get_lux_data(client)); + input_sync(input); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id isl29023_id[] = { + {"isl29023", 0}, + {} +}; + +static int isl29023_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + dev_dbg(dev, "suspend\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + isl_set_mod(client, ISL_MOD_POWERDOWN); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 suspend call, \n", __func__); + return 0; +} + +static int isl29023_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + dev_dbg(dev, "resume\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s isl29023 resume call, \n", __func__); + return 0; +} + +MODULE_DEVICE_TABLE(i2c, isl29023_id); + +/*static const struct dev_pm_ops isl29023_pm_ops = { + .runtime_suspend = isl29023_runtime_suspend, + .runtime_resume = isl29023_runtime_resume, +}; + +static struct i2c_board_info isl_info = { + I2C_BOARD_INFO("isl29023", 0x44), +}; + +static struct i2c_driver isl29023_driver = { + .driver = { + .name = "isl29023", + .pm = &isl29023_pm_ops, + }, + .probe = isl29023_probe, + .remove = isl29023_remove, + .id_table = isl29023_id, + .detect = isl29023_detect, + //.address_data = &addr_data, +};*/ + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmad_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_data(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = ISL29023_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("Isl29023_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmad_read, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmad_fops, +}; + +static void isl29023_early_suspend(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void isl29023_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + + +static int +isl29023_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int res=0; + + struct isl_device* idev = kzalloc(sizeof(struct isl_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + android_lsensor_kobj = kobject_create_and_add("android_lsensor", NULL); + if (android_lsensor_kobj == NULL) { + errlog( + "lsensor_sysfs_init:"\ + "subsystem_register failed\n"); + res = -ENOMEM; + goto err_kobjetc_create; + } + res = sysfs_create_group(android_lsensor_kobj, &m_isl_gr); + if (res) { + //pr_warn("isl29023: device create file failed!!\n"); + printk(KERN_INFO MODULE_NAME ": %s isl29023 device create file failed\n", __func__); + res = -EINVAL; + goto err_sysfs_create; + } + +/* last mod is ALS continuous */ + last_mod = 5; + //pm_runtime_enable(&client->dev); + idev->input_poll_dev = input_allocate_polled_device(); + if(!idev->input_poll_dev) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + idev->input_poll_dev->private = idev; + idev->input_poll_dev->poll = isl_input_lux_poll; + idev->input_poll_dev->poll_interval = 100;//50; + idev->input_poll_dev->input->open = isl_input_open; + idev->input_poll_dev->input->close = isl_input_close; + idev->input_poll_dev->input->name = "lsensor_lux"; + idev->input_poll_dev->input->id.bustype = BUS_I2C; + idev->input_poll_dev->input->dev.parent = &client->dev; + input_set_drvdata(idev->input_poll_dev->input, idev); + input_set_capability(idev->input_poll_dev->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_dev->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmad_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_register; + } + res = input_register_polled_device(idev->input_poll_dev); + if(res < 0) + goto err_input_register_device; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = isl29023_early_suspend; + idev->earlysuspend.resume = isl29023_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("isl29023 probe succeed!\n"); + return 0; +err_input_register_device: + misc_deregister(&mmad_device); + input_free_polled_device(idev->input_poll_dev); +err_misc_register: +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); +err_sysfs_create: + kobject_del(android_lsensor_kobj); +err_kobjetc_create: + kfree(idev); + return res; +} + +static int isl29023_remove(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmad_device); + input_unregister_polled_device(idev->input_poll_dev); + input_free_polled_device(idev->input_poll_dev); + sysfs_remove_group(android_lsensor_kobj, &m_isl_gr); + kobject_del(android_lsensor_kobj); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s isl29023 remove call, \n", __func__); + return 0; +} + +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + struct i2c_client *client = l_sensorconfig->client; + + mutex_lock(&mutex); + + isl_set_mod(client, ISL_MOD_POWERDOWN); + + mutex_unlock(&mutex); + + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + printk("<<<%s\n", __FUNCTION__); + struct i2c_client *client = l_sensorconfig->client; + + + + +RETRY: + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + isl_set_mod(client, last_mod); + ret = isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + +static int __init sensor_isl29023_init(void) +{ + printk(KERN_INFO MODULE_NAME ": %s isl29023 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even isl29023_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&isl29023_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (isl29023_detect(this_client)) + { + errlog("Can't find light sensor isl29023!\n"); + goto detect_fail; + } + if(isl29023_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + int ret = 0; + ret = platform_device_register(&lsdev); + if (ret){ + printk("<<