Merge remote-tracking branch 'origin/upstream/linux-linaro-lsk-v3.10-android+android...
[firefly-linux-kernel-4.4.55.git] / drivers / input / lightsensor / cm3217.c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/init.h>
4 #include <linux/device.h>
5 #include <linux/err.h>
6 #include <linux/io.h>
7 #include <linux/adc.h>
8 #include <linux/delay.h>
9 #include <linux/fs.h>
10 #include <linux/sched.h>
11 #include <linux/pm.h>
12 #include <linux/sysctl.h>
13 #include <linux/miscdevice.h>
14 #include <linux/slab.h>
15 #include <asm/gpio.h>
16 #include <asm/uaccess.h>
17 #include <linux/timer.h>
18 #include <linux/input.h>
19 #include <linux/ioctl.h>
20 //#include <mach/rk29_sdk_io.h>
21 #include <mach/board.h> 
22 #include <linux/platform_device.h>
23 #ifdef CONFIG_HAS_EARLYSUSPEND
24 #include <linux/earlysuspend.h>
25 #endif
26
27 #define DEBUG   0
28
29 #if DEBUG
30 #define DBG(X...)       printk(KERN_NOTICE X)
31 #else
32 #define DBG(X...)
33 #endif
34
35 #define CM3217_I2C_RATE         (200*1000)
36 #define CM3217_ADDR_COM1        0x10
37 #define CM3217_ADDR_COM2        0x11
38 #define CM3217_ADDR_DATA_MSB    0x10
39 #define CM3217_ADDR_DATA_LSB    0x11
40
41 #define CM3217_COM1_VALUE       0xA7    // (GAIN1:GAIN0)=10, (IT_T1:IT_TO)=01,WMD=1,SD=1,
42 #define CM3217_COM2_VALUE       0xA0    //100ms
43
44
45 #define SENSOR_ON       1
46 #define SENSOR_OFF      0
47 #define LIGHTSENSOR_IOCTL_MAGIC 'l'
48 #define LIGHTSENSOR_IOCTL_GET_ENABLED    _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) 
49 #define LIGHTSENSOR_IOCTL_ENABLE         _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) 
50 #define LIGHTSENSOR_IOCTL_DISABLE        _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *)
51
52 struct cm3217_data {
53         struct i2c_client       *client;
54         struct timer_list       timer;
55         struct work_struct      timer_work;
56         struct input_dev        *input;
57         int power_pin;
58         int irq_pin;
59         int status;
60 };
61 #ifdef CONFIG_HAS_EARLYSUSPEND
62 static struct early_suspend cm3217_early_suspend;
63 #endif
64 static struct cm3217_data *glight;
65
66 static int cm3217_command_set(struct i2c_client *client, char *buf, int num)
67 {
68         int ret = 0;
69         ret = i2c_master_normal_send(client, buf, num, CM3217_I2C_RATE);
70         
71         return (ret == num) ? 0 : ret;
72 }
73
74 static int cm3217_command_get(struct i2c_client *client, char *buf, int num)
75 {
76         int ret = 0;
77         ret = i2c_master_normal_recv(client, buf, num, CM3217_I2C_RATE);
78         
79         return (ret == num) ? 0 : ret;
80 }
81
82
83 static int cm3217_start(struct cm3217_data *data)
84 {
85         struct cm3217_data *cm3217 = data;
86         char buf = 0;
87         if(cm3217->status)
88                 return 0;
89         
90         //if(cm3217->power_pin != INVALID_GPIO)
91         //gpio_direction_output(cm3217->power_pin,0);//level = 0 Sensor ON
92         
93         buf = CM3217_COM1_VALUE & 0xfe ;        //SD=0
94         cm3217->client->addr = CM3217_ADDR_COM1;
95         cm3217_command_set(cm3217->client, &buf, 1);
96         
97         cm3217->status = SENSOR_ON;
98         cm3217->timer.expires  = jiffies + 1*HZ;
99         add_timer(&cm3217->timer);
100         DBG("cm3217 light sensor start\n");
101         return 0;
102 }
103
104 static int cm3217_stop(struct cm3217_data *data)
105 {
106         struct cm3217_data *cm3217 = data;
107         char buf = 0;
108         if(cm3217->status == 0)
109                 return 0;
110         
111         //if(cm3217->power_pin != INVALID_GPIO)
112         //gpio_direction_output(cm3217->power_pin,1);//level = 1 Sensor OFF
113         
114         buf = CM3217_COM1_VALUE | 0x01 ;        //SD=1
115         cm3217->client->addr = CM3217_ADDR_COM1;
116         cm3217_command_set(cm3217->client, &buf, 1);
117         
118         cm3217->status = SENSOR_OFF;
119         del_timer(&cm3217->timer);
120         DBG("cm3217 light sensor stop\n");
121         return 0;
122 }
123
124 #ifdef CONFIG_HAS_EARLYSUSPEND
125 static void cm3217_suspend(struct early_suspend *h)
126 {
127         struct cm3217_data *cm3217 = glight;
128         int status = cm3217->status;
129         cm3217_stop(cm3217);
130         cm3217->status = status;
131         DBG("Light Sensor cm3217 enter suspend cm3217->status %d\n",cm3217->status);
132 }
133
134 static void cm3217_resume(struct early_suspend *h)
135 {
136         struct cm3217_data *cm3217 = glight;
137         if(cm3217->status == SENSOR_ON)
138         cm3217_start(cm3217);
139         DBG("Light Sensor cm3217 enter resume cm3217->status %d\n",cm3217->status);
140 }
141 #endif
142 static int cm3217_open(struct inode *indoe, struct file *file)
143 {
144         return 0;
145 }
146
147 static int cm3217_release(struct inode *inode, struct file *file)
148 {
149         return 0;
150 }
151
152
153 static long cm3217_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
154 {
155         unsigned int *argp = (unsigned int *)arg;       
156         struct cm3217_data *cm3217 = glight;
157         switch(cmd){
158                 case LIGHTSENSOR_IOCTL_GET_ENABLED:
159                         *argp = cm3217->status;
160                         break;
161                 case LIGHTSENSOR_IOCTL_ENABLE:
162                         if(*argp)
163                                 cm3217_start(cm3217);
164                         else
165                                 cm3217_stop(cm3217);
166                         break;
167                 default:break;
168         }
169         return 0;
170 }
171
172 static void cm3217_value_report(struct input_dev *input, int data)
173 {
174         unsigned char index = 0;
175         if(data <= 10){
176                 index = 0;goto report;
177         }
178         else if(data <= 160){
179                 index = 1;goto report;
180         }
181         else if(data <= 225){
182                 index = 2;goto report;
183         }
184         else if(data <= 320){
185                 index = 3;goto report;
186         }
187         else if(data <= 640){
188                 index = 4;goto report;
189         }
190         else if(data <= 1280){
191                 index = 5;goto report;
192         }
193         else if(data <= 2600){
194                 index = 6;goto report;
195         }
196         else{
197                 index = 7;goto report;
198         }
199
200 report:
201         DBG("cm3217 report data=%d,index = %d\n",data,index);
202         input_report_abs(input, ABS_MISC, index);
203         input_sync(input);
204         return;
205 }
206
207 static void adc_timer(unsigned long data)
208 {
209         struct cm3217_data *cm3217=(struct cm3217_data *)data;
210         schedule_work(&cm3217->timer_work);
211 }
212
213 static void adc_timer_work(struct work_struct *work)
214 {
215         int result = 0;
216         struct cm3217_data *cm3217 = container_of(work, struct cm3217_data,timer_work);
217         char msb = 0, lsb = 0;
218
219         cm3217->client->addr = CM3217_ADDR_DATA_LSB;
220         cm3217_command_get(cm3217->client, &lsb, 1);
221         cm3217->client->addr = CM3217_ADDR_DATA_MSB;
222         cm3217_command_get(cm3217->client, &msb, 1);
223         result = ((msb << 8) | lsb) & 0xffff;
224         cm3217_value_report(cm3217->input, result);
225         DBG("%s:result=%d\n",__func__,result);
226         
227         if(cm3217->status){
228                 cm3217->timer.expires  = jiffies + 1*HZ;
229                 add_timer(&cm3217->timer);
230         }
231 }
232
233 static struct file_operations cm3217_fops = {
234         .owner = THIS_MODULE,
235         .open = cm3217_open,
236         .release = cm3217_release,
237         .unlocked_ioctl = cm3217_ioctl,
238 };
239
240 static struct miscdevice cm3217_device = {
241         .minor = MISC_DYNAMIC_MINOR,
242         .name = "lightsensor",
243         .fops = &cm3217_fops,
244 };
245
246 static int cm3217_probe(struct i2c_client *client, const struct i2c_device_id *id)
247 {
248         struct cm3217_data *cm3217;     
249         struct cm3217_platform_data *pdata = pdata = client->dev.platform_data; 
250         char com1 = CM3217_COM1_VALUE, com2 = CM3217_COM2_VALUE;
251         int err;
252         
253         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
254         {
255                 dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");
256                 err = -ENODEV;
257                 goto alloc_memory_fail;
258         }
259                 
260         cm3217 = kmalloc(sizeof(struct cm3217_data), GFP_KERNEL);
261         if(!cm3217){
262                 printk("cm3217 alloc memory err !!!\n");
263                 err = -ENOMEM;
264                 goto alloc_memory_fail;
265         }       
266         
267         if(pdata->init_platform_hw)
268         pdata->init_platform_hw();
269
270         cm3217->client = client;
271         i2c_set_clientdata(client, cm3217);     
272         cm3217->power_pin = pdata->power_pin;
273         cm3217->irq_pin = pdata->irq_pin;
274         cm3217->status = SENSOR_OFF;    
275         glight = cm3217;
276
277         //init cm3217
278         client->addr = CM3217_ADDR_COM1;
279         cm3217_command_set(client, &com1, 1);   
280         client->addr = CM3217_ADDR_COM2;
281         cm3217_command_set(client, &com2, 1);   
282         
283         cm3217->input = input_allocate_device();
284         if (!cm3217->input) {
285                 err = -ENOMEM;
286                 printk(KERN_ERR"cm3217: Failed to allocate input device\n");
287                 goto exit_input_allocate_device_failed;
288         }
289         set_bit(EV_ABS, cm3217->input->evbit);
290         /* light sensor data */
291         input_set_abs_params(cm3217->input, ABS_MISC, 0, 10, 0, 0);
292         cm3217->input->name = "lightsensor-level";
293
294         err = input_register_device(cm3217->input);
295         if (err < 0) {
296                 printk(KERN_ERR"cm3217: Unable to register input device: %s\n",cm3217->input->name);                                            
297                 goto exit_input_register_device_failed;
298         }
299 /*      
300         if(cm3217->power_pin != INVALID_GPIO)
301         {
302                 gpio_request(cm3217->power_pin, "cm3217_power_pin");
303                 gpio_pull_updown(cm3217->power_pin,PullDisable); 
304         }
305 */      
306         INIT_WORK(&cm3217->timer_work, adc_timer_work);
307         setup_timer(&cm3217->timer, adc_timer, (unsigned long)cm3217);
308         err = misc_register(&cm3217_device);
309         if (err < 0) {
310                 printk(KERN_ERR"cm3217_probe: lightsensor_device register failed\n");
311                 goto exit_misc_register_fail;
312         }
313         printk("lightsensor cm3217 driver created !\n");
314         //cm3217_start(cm3217);
315 #ifdef CONFIG_HAS_EARLYSUSPEND
316         cm3217_early_suspend.suspend = cm3217_suspend;
317         cm3217_early_suspend.resume = cm3217_resume;
318         cm3217_early_suspend.level = 0x2;
319         register_early_suspend(&cm3217_early_suspend);
320 #endif
321         return 0;
322 exit_misc_register_fail:
323         //gpio_free(pdata->power_pin);
324         input_unregister_device(cm3217->input);
325 exit_input_register_device_failed:
326         input_free_device(cm3217->input);
327 exit_input_allocate_device_failed:
328         kfree(cm3217);
329 alloc_memory_fail:
330         printk("%s error\n",__FUNCTION__);
331         return err;
332 }
333
334 static int cm3217_remove(struct i2c_client *client)
335 {       
336         struct cm3217_data *cm3217 = i2c_get_clientdata(client);
337         kfree(cm3217);
338         input_free_device(cm3217->input);
339         input_unregister_device(cm3217->input);
340         misc_deregister(&cm3217_device);
341         return 0;
342 }
343
344 static const struct i2c_device_id cm3217_id[] = {
345         { "lightsensor", 0 },
346 };
347
348 static void cm3217_shutdown(struct i2c_client *client)
349 {
350 #ifdef CONFIG_HAS_EARLYSUSPEND
351         unregister_early_suspend(&cm3217_early_suspend);
352 #endif
353 }
354
355 static struct i2c_driver cm3217_driver = {
356         .probe = cm3217_probe,
357         .remove = __devexit_p(cm3217_remove),
358         .shutdown = cm3217_shutdown,
359         .id_table = cm3217_id,
360         .driver = {
361                 .owner = THIS_MODULE,
362                 .name = "lightsensor",
363         }
364 };
365
366
367 static int __init cm3217_init(void)
368 {
369         return i2c_add_driver(&cm3217_driver);
370 }
371
372 static void __exit cm3217_exit(void)
373 {
374         i2c_del_driver(&cm3217_driver);
375 }
376
377 module_init(cm3217_init);
378 module_exit(cm3217_exit);