From: lw <lw@rock-chips.com>
Date: Tue, 6 Mar 2012 10:09:00 +0000 (+0800)
Subject: rk30:add light sensor cm3217 support
X-Git-Tag: firefly_0821_release~9595^2~87
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=d014c98f10d855a766e0761e52b7ae75787bd610;p=firefly-linux-kernel-4.4.55.git

rk30:add light sensor cm3217 support
---

diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c
index f13505f054ae..c28a73f87299 100755
--- a/arch/arm/mach-rk30/board-rk30-sdk.c
+++ b/arch/arm/mach-rk30/board-rk30-sdk.c
@@ -396,6 +396,48 @@ static struct l3g4200d_platform_data l3g4200d_info = {
 
 #endif
 
+#ifdef CONFIG_LS_CM3217
+
+#define CM3217_POWER_PIN 	INVALID_GPIO
+#define CM3217_IRQ_PIN		INVALID_GPIO
+static int cm3217_init_hw(void)
+{
+#if 0
+	if (gpio_request(CM3217_POWER_PIN, NULL) != 0) {
+	gpio_free(CM3217_POWER_PIN);
+	printk("%s: request cm3217 power pin error\n", __func__);
+	return -EIO;
+	}
+	gpio_pull_updown(CM3217_POWER_PIN, PullDisable);
+
+	if (gpio_request(CM3217_IRQ_PIN, NULL) != 0) {
+	gpio_free(CM3217_IRQ_PIN);
+	printk("%s: request cm3217 int pin error\n", __func__);
+	return -EIO;
+	}
+	gpio_pull_updown(CM3217_IRQ_PIN, PullDisable);
+#endif
+	return 0;
+}
+
+static void cm3217_exit_hw(void)
+{
+#if 0
+	gpio_free(CM3217_POWER_PIN);
+	gpio_free(CM3217_IRQ_PIN);
+#endif
+	return;
+}
+
+struct cm3217_platform_data cm3217_info = {
+	.irq_pin = CM3217_IRQ_PIN,
+	.power_pin = CM3217_POWER_PIN,
+	.init_platform_hw = cm3217_init_hw,
+	.exit_platform_hw = cm3217_exit_hw,
+};
+#endif
+
+
 
 #ifdef CONFIG_FB_ROCKCHIP
 static struct resource resource_fb[] = {
@@ -498,6 +540,15 @@ static struct i2c_board_info __initdata i2c2_info[] = {
 				.platform_data = &goodix_info,
 		    },
 #endif
+#if defined (CONFIG_LS_CM3217)
+	{
+		.type           = "lightsensor",
+		.addr           = 0x20,
+		.flags          = 0,
+		.irq            = CM3217_IRQ_PIN,
+		.platform_data  = &cm3217_info,
+	},
+#endif
 
 };
 #endif
diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h
index 7e6aeb697cea..a75fc54886ea 100755
--- a/arch/arm/plat-rk/include/plat/board.h
+++ b/arch/arm/plat-rk/include/plat/board.h
@@ -105,6 +105,13 @@ struct goodix_platform_data {
     void    (*exit_platform_hw)(void);
 };
 
+struct cm3217_platform_data {
+	int irq_pin;
+	int power_pin;
+	int     (*init_platform_hw)(void);
+	void    (*exit_platform_hw)(void);
+};
+
 
 
 #define BOOT_MODE_NORMAL		0
diff --git a/drivers/input/lightsensor/Kconfig b/drivers/input/lightsensor/Kconfig
index f42def7d4e26..a95de5a87d47 100644
--- a/drivers/input/lightsensor/Kconfig
+++ b/drivers/input/lightsensor/Kconfig
@@ -14,9 +14,17 @@ if LIGHT_SENSOR_DEVICE
 config CM3202
   bool "cm3202"
 	depends on LIGHT_SENSOR_DEVICE
-	default y
+	default n
 	help	 
 	  To have support for your specific gsesnor you will have to
 	  select the proper drivers which depend on this option.
 
+config LS_CM3217
+  bool "cm3217"
+	depends on LIGHT_SENSOR_DEVICE
+	default n
+	help	 
+	  To have support for your specific gsesnor you will have to
+	  select the proper drivers which depend on this option.
+	  
 endif
diff --git a/drivers/input/lightsensor/Makefile b/drivers/input/lightsensor/Makefile
index c00691dd14fd..08554c7dc42c 100644
--- a/drivers/input/lightsensor/Makefile
+++ b/drivers/input/lightsensor/Makefile
@@ -1,3 +1,5 @@
 # gsensor drivers
 
 obj-$(CONFIG_CM3202) 	+= cm3202.o
+obj-$(CONFIG_LS_CM3217) 	+= cm3217.o
+
diff --git a/drivers/input/lightsensor/cm3217.c b/drivers/input/lightsensor/cm3217.c
new file mode 100755
index 000000000000..6d0bb9e27b05
--- /dev/null
+++ b/drivers/input/lightsensor/cm3217.c
@@ -0,0 +1,351 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/adc.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <asm/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/timer.h>
+#include <linux/input.h>
+#include <linux/ioctl.h>
+//#include <mach/rk29_sdk_io.h>
+#include <mach/board.h> 
+#include <linux/platform_device.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#define DEBUG 	0
+
+#if DEBUG
+#define DBG(X...)	printk(KERN_NOTICE X)
+#else
+#define DBG(X...)
+#endif
+
+#define CM3217_I2C_RATE		(200*1000)
+#define CM3217_ADDR_COM1	0x20
+#define CM3217_ADDR_COM2	0x22
+#define CM3217_ADDR_DATA_MSB	0x21
+#define CM3217_ADDR_DATA_LSB	0x23
+
+#define CM3217_COM1_VALUE	0xA4	// (GAIN1:GAIN0)=10, (IT_T1:IT_TO)=01,WMD=0,SD=0,
+#define CM3217_COM2_VALUE	0xA0	//100ms
+
+
+#define SENSOR_ON	1
+#define SENSOR_OFF	0
+#define LIGHTSENSOR_IOCTL_MAGIC 'l'
+#define LIGHTSENSOR_IOCTL_GET_ENABLED	 _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) 
+#define LIGHTSENSOR_IOCTL_ENABLE	 _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) 
+#define LIGHTSENSOR_IOCTL_DISABLE        _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *)
+
+struct cm3217_data {
+	struct i2c_client	*client;
+	struct timer_list	timer;
+	struct work_struct	timer_work;
+	struct input_dev	*input;
+	int power_pin;
+	int irq_pin;
+	int status;
+};
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static struct early_suspend cm3217_early_suspend;
+#endif
+static struct cm3217_data *glight;
+
+static int cm3217_command_set(struct i2c_client *client, char *buf, int num)
+{
+	int ret = 0;
+	ret = i2c_master_normal_send(client, buf, num, CM3217_I2C_RATE);
+	
+	return (ret == num) ? 0 : ret;
+}
+
+static int cm3217_command_get(struct i2c_client *client, char *buf, int num)
+{
+	int ret = 0;
+	ret = i2c_master_normal_send(client, buf, num, CM3217_I2C_RATE);
+	
+	return (ret == num) ? 0 : ret;
+}
+
+
+static int cm3217_start(struct cm3217_data *data)
+{
+	struct cm3217_data *cm3217 = data;
+	char buf = 0;
+	if(cm3217->status)
+		return 0;
+	
+	//if(cm3217->power_pin != INVALID_GPIO)
+	//gpio_direction_output(cm3217->power_pin,0);//level = 0 Sensor ON
+	
+	buf = CM3217_COM1_VALUE | 0x01 ;	//SD=1
+	cm3217_command_set(cm3217->client, &buf, 1);
+	
+	cm3217->status = SENSOR_ON;
+	cm3217->timer.expires  = jiffies + 1*HZ;
+	add_timer(&cm3217->timer);
+	DBG("cm3217 light sensor start\n");
+	return 0;
+}
+
+static int cm3217_stop(struct cm3217_data *data)
+{
+	struct cm3217_data *cm3217 = data;
+	char buf = 0;
+	if(cm3217->status == 0)
+		return 0;
+	
+	//if(cm3217->power_pin != INVALID_GPIO)
+	//gpio_direction_output(cm3217->power_pin,1);//level = 1 Sensor OFF
+	
+	buf = CM3217_COM1_VALUE & 0xfe ;	//SD=0
+	cm3217_command_set(cm3217->client, &buf, 1);
+	
+	cm3217->status = SENSOR_OFF;
+	del_timer(&cm3217->timer);
+	DBG("cm3217 light sensor stop\n");
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cm3217_suspend(struct early_suspend *h)
+{
+	struct cm3217_data *cm3217 = glight;
+	cm3217_stop(cm3217);
+	DBG("Light Sensor cm3217 enter suspend cm3217->status %d\n",cm3217->status);
+}
+
+static void cm3217_resume(struct early_suspend *h)
+{
+	struct cm3217_data *cm3217 = glight;
+	cm3217_start(cm3217);
+	DBG("Light Sensor cm3217 enter resume cm3217->status %d\n",cm3217->status);
+}
+#endif
+static int cm3217_open(struct inode *indoe, struct file *file)
+{
+	return 0;
+}
+
+static int cm3217_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static long cm3217_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int *argp = (unsigned int *)arg;	
+	struct cm3217_data *cm3217 = glight;
+	switch(cmd){
+		case LIGHTSENSOR_IOCTL_GET_ENABLED:
+			*argp = cm3217->status;
+			break;
+		case LIGHTSENSOR_IOCTL_ENABLE:
+			if(*argp)
+				cm3217_start(cm3217);
+			else
+				cm3217_stop(cm3217);
+			break;
+		default:break;
+	}
+	return 0;
+}
+
+static void cm3217_value_report(struct input_dev *input, int data)
+{
+	unsigned char index = 0;
+	if(data <= 10){
+		index = 0;goto report;
+	}
+	else if(data <= 160){
+		index = 1;goto report;
+	}
+	else if(data <= 225){
+		index = 2;goto report;
+	}
+	else if(data <= 320){
+		index = 3;goto report;
+	}
+	else if(data <= 640){
+		index = 4;goto report;
+	}
+	else if(data <= 1280){
+		index = 5;goto report;
+	}
+	else if(data <= 2600){
+		index = 6;goto report;
+	}
+	else{
+		index = 7;goto report;
+	}
+
+report:
+	DBG("cm3217 report data=%d,index = %d\n",data,index);
+	input_report_abs(input, ABS_MISC, index);
+	input_sync(input);
+	return;
+}
+
+static void adc_timer(unsigned long data)
+{
+	struct cm3217_data *cm3217=(struct cm3217_data *)data;
+	schedule_work(&cm3217->timer_work);
+}
+
+static void adc_timer_work(struct work_struct *work)
+{
+	int result = 0;
+	struct cm3217_data *cm3217 = container_of(work, struct cm3217_data,timer_work);
+	char msb = 0, lsb = 0;
+
+	cm3217->client->addr = CM3217_ADDR_DATA_LSB;
+	cm3217_command_get(cm3217->client, &lsb, 1);
+	cm3217->client->addr = CM3217_ADDR_DATA_MSB;
+	cm3217_command_get(cm3217->client, &msb, 1);
+	result = ((msb << 8) | lsb) & 0xffff;
+	cm3217_value_report(cm3217->input, result);
+	DBG("%s:result=%d\n",__func__,result);
+	
+	if(cm3217->status){
+		cm3217->timer.expires  = jiffies + 3*HZ;
+		add_timer(&cm3217->timer);
+	}
+}
+
+static struct file_operations cm3217_fops = {
+	.owner = THIS_MODULE,
+	.open = cm3217_open,
+	.release = cm3217_release,
+	.unlocked_ioctl = cm3217_ioctl,
+};
+
+static struct miscdevice cm3217_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "lightsensor",
+	.fops = &cm3217_fops,
+};
+
+static int cm3217_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct cm3217_data *cm3217;	
+	struct cm3217_platform_data *pdata = pdata = client->dev.platform_data;	
+	char com1 = CM3217_COM1_VALUE, com2 = CM3217_COM2_VALUE;
+	int err;
+	
+	cm3217 = kmalloc(sizeof(struct cm3217_data), GFP_KERNEL);
+	if(!cm3217){
+		printk("cm3217 alloc memory err !!!\n");
+		err = -ENOMEM;
+		goto alloc_memory_fail;
+	}	
+	
+	if(pdata->init_platform_hw)
+	pdata->init_platform_hw();
+
+	cm3217->client = client;
+	i2c_set_clientdata(client, cm3217);	
+	cm3217->power_pin = pdata->power_pin;
+	cm3217->irq_pin = pdata->irq_pin;
+	cm3217->status = SENSOR_OFF;	
+	glight = cm3217;
+
+	//init cm3217
+	cm3217_command_set(client, &com1, 1);
+	cm3217_command_set(client, &com2, 1);	
+	
+	cm3217->input = input_allocate_device();
+	if (!cm3217->input) {
+		err = -ENOMEM;
+		printk(KERN_ERR"cm3217: Failed to allocate input device\n");
+		goto exit_input_allocate_device_failed;
+	}
+	set_bit(EV_ABS, cm3217->input->evbit);
+	/* light sensor data */
+	input_set_abs_params(cm3217->input, ABS_MISC, 0, 0x3ff, 0, 0);
+	cm3217->input->name = "lightsensor";
+
+	err = input_register_device(cm3217->input);
+	if (err < 0) {
+		printk(KERN_ERR"cm3217: Unable to register input device: %s\n",cm3217->input->name);						
+		goto exit_input_register_device_failed;
+	}
+/*	
+	if(cm3217->power_pin != INVALID_GPIO)
+	{
+		gpio_request(cm3217->power_pin, "cm3217_power_pin");
+		gpio_pull_updown(cm3217->power_pin,PullDisable); 
+	}
+*/	
+	INIT_WORK(&cm3217->timer_work, adc_timer_work);
+	setup_timer(&cm3217->timer, adc_timer, (unsigned long)cm3217);
+	err = misc_register(&cm3217_device);
+	if (err < 0) {
+		printk(KERN_ERR"cm3217_probe: lightsensor_device register failed\n");
+		goto exit_misc_register_fail;
+	}
+	printk("lightsensor cm3217 driver created !\n");
+	//cm3217_start(light);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	cm3217_early_suspend.suspend = cm3217_suspend;
+	cm3217_early_suspend.resume = cm3217_resume;
+	cm3217_early_suspend.level = 0x2;
+	register_early_suspend(&cm3217_early_suspend);
+#endif
+	return 0;
+exit_misc_register_fail:
+	//gpio_free(pdata->power_pin);
+	input_unregister_device(cm3217->input);
+exit_input_register_device_failed:
+	input_free_device(cm3217->input);
+exit_input_allocate_device_failed:
+	kfree(cm3217);
+alloc_memory_fail:
+	printk("%s error\n",__FUNCTION__);
+	return err;
+}
+
+static int cm3217_remove(struct i2c_client *client)
+{	
+	struct cm3217_data *cm3217 = i2c_get_clientdata(client);
+	kfree(cm3217);
+	input_free_device(cm3217->input);
+	input_unregister_device(cm3217->input);
+	misc_deregister(&cm3217_device);
+	return 0;
+}
+
+static struct i2c_driver cm3217_driver = {
+	.probe = cm3217_probe,
+	.remove = __devexit_p(cm3217_remove),
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "lightsensor",
+	}
+};
+
+
+static int __init cm3217_init(void)
+{
+	return i2c_add_driver(&cm3217_driver);
+}
+
+static void __exit cm3217_exit(void)
+{
+	i2c_del_driver(&cm3217_driver);
+}
+
+module_init(cm3217_init);
+module_exit(cm3217_exit);