Merge "wlan_cfg80211: Set the hidden ssid scan properly." into tizen
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / misc / st480.c
1 /*
2  * Copyright (C) 2012 Senodia.
3  *
4  * Author: Tori Xu <xuezhi_xu@senodia.com>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 #include <linux/st480.h>
17 #include <linux/module.h>
18 #include <linux/of_device.h>
19
20 struct st480_data {
21         struct i2c_client *client;
22         struct input_dev *input_dev;
23         struct st480_platform_data *pdata;
24         struct delayed_work work;
25 };
26
27 static struct st480_data *st480;
28
29 static atomic_t m_flag;
30 static atomic_t mv_flag;
31
32 static atomic_t open_count;
33 static atomic_t open_flag;
34 static atomic_t reserve_open_flag;
35
36 volatile static short st480_delay = ST480_DEFAULT_DELAY;
37
38 struct mag_3 {
39         s16  mag_x,
40              mag_y,
41              mag_z;
42 };
43 volatile static struct mag_3 mag;
44
45 /*
46  * i2c transfer
47  * read/write
48  */
49 #if ST480_DATA_TRANSFER
50 static int st480_i2c_data_transfer(struct i2c_client *client, int len, char *buf, int length)
51 {
52         struct i2c_msg msgs[] = {
53                 {
54                         .addr  =  client->addr,
55                         .flags  =  0,
56                         .len  =  len,
57                         .buf  =  buf,
58                 },
59                 {
60                         .addr  =  client->addr,
61                         .flags  = I2C_M_RD,
62                         .len  =  length,
63                         .buf  =  buf,
64                 },
65         };
66
67         if(i2c_transfer(client->adapter, msgs, 2) < 0) {
68                 pr_err("megnetic_i2c_read_data: transfer error\n");
69                 return EIO;
70         } else
71                 return 0;
72 }
73 #endif
74
75 #if ST480_SMBUS_READ_BYTE
76 static int st480_smbus_read_byte(struct i2c_client *client,
77                                  unsigned char reg_addr, unsigned char *data)
78 {
79         s32 dummy;
80         dummy = i2c_smbus_read_byte_data(client, reg_addr);
81         if (dummy < 0)
82                 return -EPERM;
83         *data = dummy & 0x000000ff;
84
85         return 0;
86 }
87 #endif
88
89 #if ST480_SMBUS_WRITE_BYTE
90 static int st480_smbus_write_byte(struct i2c_client *client,
91                                   unsigned char reg_addr, unsigned char *data)
92 {
93         s32 dummy;
94         dummy = i2c_smbus_write_byte_data(client, reg_addr, *data);
95         if (dummy < 0)
96                 return -EPERM;
97         return 0;
98 }
99 #endif
100
101 #if ST480_SMBUS_READ_BYTE_BLOCK
102 static int st480_smbus_read_byte_block(struct i2c_client *client,
103                                        unsigned char reg_addr, unsigned char *data, unsigned char len)
104 {
105         s32 dummy;
106         dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data);
107         if (dummy < 0)
108                 return -EPERM;
109         return 0;
110 }
111 #endif
112
113 #if ST480_SMBUS_WRITE_BYTE_BLOCK
114 static int st480_smbus_write_byte_block(struct i2c_client *client,
115                                         unsigned char reg_addr, unsigned char *data, unsigned char len)
116 {
117         s32 dummy;
118         dummy = i2c_smbus_write_i2c_block_data(client, reg_addr, len, data);
119         if (dummy < 0)
120                 return -EPERM;
121         return 0;
122 }
123 #endif
124
125 /*
126  * Device detect and init
127  *
128  */
129 static int st480_setup(struct i2c_client *client)
130 {
131         int ret;
132         unsigned char buf[5];
133
134         memset(buf, 0, 5);
135
136 #if IC_CHECK
137         buf[0] = READ_REGISTER_CMD;
138         buf[1] = 0x00;
139         ret = 0;
140         while(st480_i2c_data_transfer(client, 2, buf, 3)!=0) {
141                 ret++;
142                 msleep(1);
143                 if(st480_i2c_data_transfer(client, 2, buf, 3)==0) {
144                         break;
145                 }
146                 if(ret > MAX_FAILURE_COUNT) {
147                         return -EIO;
148                 }
149         }
150
151         if(buf[2] != ST480_DEVICE_ID) {
152                 return -ENODEV;
153         }
154 #endif
155
156 //init register step 1
157         buf[0] = WRITE_REGISTER_CMD;
158         buf[1] = ONE_INIT_DATA_HIGH;
159         buf[2] = ONE_INIT_DATA_LOW;
160         buf[3] = ONE_INIT_REG;
161         ret = 0;
162         while(st480_i2c_data_transfer(client, 4, buf, 1)!=0) {
163                 ret++;
164                 msleep(1);
165                 if(st480_i2c_data_transfer(client, 4, buf, 1)==0) {
166                         break;
167                 }
168                 if(ret > MAX_FAILURE_COUNT) {
169                         return -EIO;
170                 }
171         }
172
173 //init register step 2
174         buf[0] = WRITE_REGISTER_CMD;
175         buf[1] = TWO_INIT_DATA_HIGH;
176         buf[2] = TWO_INIT_DATA_LOW;
177         buf[3] = TWO_INIT_REG;
178         ret = 0;
179         while(st480_i2c_data_transfer(client, 4, buf, 1)!=0) {
180                 ret++;
181                 msleep(1);
182                 if(st480_i2c_data_transfer(client, 4, buf, 1)==0) {
183                         break;
184                 }
185                 if(ret > MAX_FAILURE_COUNT) {
186                         return -EIO;
187                 }
188         }
189
190 //set calibration register
191         buf[0] = WRITE_REGISTER_CMD;
192         buf[1] = CALIBRATION_DATA_HIGH;
193         buf[2] = CALIBRATION_DATA_LOW;
194         buf[3] = CALIBRATION_REG;
195         ret = 0;
196         while(st480_i2c_data_transfer(client, 4, buf, 1)!=0) {
197                 ret++;
198                 msleep(1);
199                 if(st480_i2c_data_transfer(client, 4, buf, 1)==0) {
200                         break;
201                 }
202                 if(ret > MAX_FAILURE_COUNT) {
203                         return -EIO;
204                 }
205         }
206
207 //set mode config
208         buf[0] = SINGLE_MEASUREMENT_MODE_CMD;
209         ret=0;
210         while(st480_i2c_data_transfer(client, 1, buf, 1)!=0) {
211                 ret++;
212                 msleep(1);
213                 if(st480_i2c_data_transfer(client, 1, buf, 1)==0) {
214                         break;
215                 }
216                 if(ret > MAX_FAILURE_COUNT) {
217                         return -EIO;
218                 }
219         }
220
221         return 0;
222 }
223
224 static void st480_work_func(void)
225 {
226         char buffer[9];
227         int ret;
228
229         /* x,y,z hardware data */
230         s16 hw_d[3] = { 0 };
231
232         memset(buffer, 0, 9);
233
234         buffer[0] = READ_MEASUREMENT_CMD;
235         ret=0;
236         while(st480_i2c_data_transfer(st480->client, 1, buffer, 9)!=0) {
237                 ret++;
238                 msleep(1);
239                 if(st480_i2c_data_transfer(st480->client, 1, buffer, 9)==0) {
240                         break;
241                 }
242                 if(ret > MAX_FAILURE_COUNT) {
243                         return;
244                 }
245         }
246
247         if(!((buffer[0]>>4) & 0X01)) {
248                 hw_d[0] = ((buffer[3]<<8)|buffer[4]);
249                 hw_d[1] = ((buffer[5]<<8)|buffer[6]);
250                 hw_d[2] = ((buffer[7]<<8)|buffer[8]);
251
252                 mag.mag_x = ((st480->pdata->negate_x) ? (-hw_d[st480->pdata->axis_map_x])
253                              : (hw_d[st480->pdata->axis_map_x]));
254                 mag.mag_y = ((st480->pdata->negate_y) ? (-hw_d[st480->pdata->axis_map_y])
255                              : (hw_d[st480->pdata->axis_map_y]));
256                 mag.mag_z = ((st480->pdata->negate_z) ? (-hw_d[st480->pdata->axis_map_z])
257                              : (hw_d[st480->pdata->axis_map_z]));
258
259                 if( ((buffer[1]<<8)|(buffer[2])) > 46244) {
260                         mag.mag_x = mag.mag_x * (1 + (70/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
261                         mag.mag_y = mag.mag_y * (1 + (70/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
262                         mag.mag_z = mag.mag_z * (1 + (70/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
263                 } else if( ((buffer[1]<<8)|(buffer[2])) < 46244) {
264                         mag.mag_x = mag.mag_x * (1 + (60/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
265                         mag.mag_y = mag.mag_y * (1 + (60/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
266                         mag.mag_z = mag.mag_z * (1 + (60/128/4096) * (((buffer[1]<<8)|(buffer[2])) - 46244));
267                 }
268
269                 SENODIADBG("st480 raw data: x = %d, y = %d, z = %d \n",mag.mag_x,mag.mag_y,mag.mag_z);
270         }
271
272         //set mode config
273         buffer[0] = SINGLE_MEASUREMENT_MODE_CMD;
274         ret=0;
275         while(st480_i2c_data_transfer(st480->client, 1, buffer, 1)!=0) {
276                 ret++;
277                 msleep(1);
278                 if(st480_i2c_data_transfer(st480->client, 1, buffer, 1)==0) {
279                         break;
280                 }
281                 if(ret > MAX_FAILURE_COUNT) {
282                         return;
283                 }
284         }
285 }
286
287 static void st480_input_func(struct work_struct *work)
288 {
289         SENODIAFUNC("st480_input_func");
290         st480_work_func();
291
292         if (atomic_read(&m_flag) || atomic_read(&mv_flag)) {
293                 input_report_abs(st480->input_dev, ABS_RX, mag.mag_x);
294                 input_report_abs(st480->input_dev, ABS_RY, mag.mag_y);
295                 input_report_abs(st480->input_dev, ABS_RZ, mag.mag_z);
296         }
297
298         input_sync(st480->input_dev);
299
300         schedule_delayed_work(&st480->work,msecs_to_jiffies(st480_delay));
301 }
302
303 static void ecs_closedone(void)
304 {
305         SENODIAFUNC("ecs_closedone");
306         atomic_set(&m_flag, 0);
307         atomic_set(&mv_flag, 0);
308 }
309
310 /***** st480 functions ***************************************/
311 static int st480_open(struct inode *inode, struct file *file)
312 {
313         int ret = -1;
314
315         SENODIAFUNC("st480_open");
316
317         if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
318                 if (atomic_cmpxchg(&open_flag, 0, 1) == 0) {
319                         atomic_set(&reserve_open_flag, 1);
320                         ret = 0;
321                 }
322         }
323
324         if(atomic_read(&reserve_open_flag)) {
325                 schedule_delayed_work(&st480->work,msecs_to_jiffies(st480_delay));
326         }
327         return ret;
328 }
329
330 static int st480_release(struct inode *inode, struct file *file)
331 {
332         SENODIAFUNC("st480_release");
333
334         atomic_set(&reserve_open_flag, 0);
335         atomic_set(&open_flag, 0);
336         atomic_set(&open_count, 0);
337
338         ecs_closedone();
339
340         cancel_delayed_work(&st480->work);
341         return 0;
342 }
343
344 #if OLD_KERNEL_VERSION
345 static int
346 st480_ioctl(struct inode *inode, struct file *file,
347             unsigned int cmd, unsigned long arg)
348 #else
349 static long
350 st480_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
351 #endif
352 {
353         void __user *argp = (void __user *)arg;
354         short flag;
355
356         SENODIADBG("enter %s\n", __func__);
357
358         switch (cmd) {
359         case ECS_IOCTL_APP_SET_MFLAG:
360         case ECS_IOCTL_APP_SET_MVFLAG:
361                 if (copy_from_user(&flag, argp, sizeof(flag))) {
362                         return -EFAULT;
363                 }
364                 if (flag < 0 || flag > 1) {
365                         return -EINVAL;
366                 }
367                 break;
368         case ECS_IOCTL_APP_SET_DELAY:
369                 if (copy_from_user(&flag, argp, sizeof(flag))) {
370                         return -EFAULT;
371                 }
372                 break;
373         default:
374                 break;
375         }
376
377         switch (cmd) {
378         case ECS_IOCTL_APP_SET_MFLAG:
379                 atomic_set(&m_flag, flag);
380                 SENODIADBG("MFLAG is set to %d", flag);
381                 break;
382         case ECS_IOCTL_APP_GET_MFLAG:
383                 flag = atomic_read(&m_flag);
384                 SENODIADBG("Mflag = %d\n",flag);
385                 break;
386         case ECS_IOCTL_APP_SET_MVFLAG:
387                 atomic_set(&mv_flag, flag);
388                 SENODIADBG("MVFLAG is set to %d", flag);
389                 break;
390         case ECS_IOCTL_APP_GET_MVFLAG:
391                 flag = atomic_read(&mv_flag);
392                 SENODIADBG("MVflag = %d\n",flag);
393                 break;
394         case ECS_IOCTL_APP_SET_DELAY:
395                 st480_delay = flag;
396                 break;
397         case ECS_IOCTL_APP_GET_DELAY:
398                 flag = st480_delay;
399                 break;
400         default:
401                 return -ENOTTY;
402         }
403
404         switch (cmd) {
405         case ECS_IOCTL_APP_GET_MFLAG:
406         case ECS_IOCTL_APP_GET_MVFLAG:
407         case ECS_IOCTL_APP_GET_DELAY:
408                 if (copy_to_user(argp, &flag, sizeof(flag))) {
409                         return -EFAULT;
410                 }
411                 break;
412         default:
413                 break;
414         }
415
416         return 0;
417 }
418
419
420 static struct file_operations st480_fops = {
421         .owner = THIS_MODULE,
422         .open = st480_open,
423         .release = st480_release,
424 #if OLD_KERNEL_VERSION
425         .ioctl = st480_ioctl,
426 #else
427         .unlocked_ioctl = st480_ioctl,
428 #endif
429 };
430
431
432 static struct miscdevice st480_device = {
433         .minor = MISC_DYNAMIC_MINOR,
434         .name = "st480",
435         .fops = &st480_fops,
436 };
437
438 /*********************************************/
439 #if ST480_AUTO_TEST
440 static int sensor_test_read(void)
441
442 {
443         st480_work_func();
444         return 0;
445 }
446
447 static int auto_test_read(void *unused)
448 {
449         while(1) {
450                 sensor_test_read();
451                 msleep(200);
452         }
453         return 0;
454 }
455 #endif
456
457 #ifdef CONFIG_OF
458 static struct st480_platform_data *st480_parse_dt(struct device *dev)
459 {
460         struct st480_platform_data *pdata;
461         struct device_node *np = dev->of_node;
462         int ret;
463         pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
464         if (!pdata) {
465                 dev_err(dev, "Could not allocate struct st480_platform_data");
466                 return NULL;
467         }
468         ret = of_property_read_u32(np, "axis_map_x", &pdata->axis_map_x);
469         if(ret){
470                 dev_err(dev, "fail to get axis_map_x\n");
471                 goto fail;
472         }
473         ret = of_property_read_u32(np, "axis_map_y", &pdata->axis_map_y);
474         if(ret){
475                 dev_err(dev, "fail to get axis_map_y\n");
476                 goto fail;
477         }
478         ret = of_property_read_u32(np, "axis_map_z", &pdata->axis_map_z);
479         if(ret){
480                 dev_err(dev, "fail to get axis_map_z\n");
481                 goto fail;
482         }
483         ret = of_property_read_u32(np, "negate_x", &pdata->negate_x);
484         if(ret){
485                 dev_err(dev, "fail to get negate_x\n");
486                 goto fail;
487         }
488         ret = of_property_read_u32(np, "negate_y", &pdata->negate_y);
489         if(ret){
490                 dev_err(dev, "fail to get negate_y\n");
491                 goto fail;
492         }
493         ret = of_property_read_u32(np, "negate_z", &pdata->negate_z);
494         if(ret){
495                 dev_err(dev, "fail to get negate_z\n");
496                 goto fail;
497         }
498        return pdata;
499 fail:
500        kfree(pdata);
501        return NULL;
502 }
503 #endif
504 int st480_probe(struct i2c_client *client, const struct i2c_device_id *id)
505 {
506         int err = 0;
507         struct st480_platform_data *pdata = client->dev.platform_data;
508
509 #if ST480_AUTO_TEST
510         struct task_struct *thread;
511 #endif
512
513         SENODIAFUNC("st480_probe");
514
515 #ifdef CONFIG_OF
516         struct device_node *np = client->dev.of_node;
517         if (np && !pdata){
518                 pdata = st480_parse_dt(&client->dev);
519                 if(pdata){
520                         client->dev.platform_data = pdata;
521                 }
522                 if(!pdata){
523                         err = -ENOMEM;
524                         goto exit_alloc_platform_data_failed;
525                 }
526         }
527 #endif
528         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
529                 printk(KERN_ERR "SENODIA st480_probe: check_functionality failed.\n");
530                 err = -ENODEV;
531                 goto exit0;
532         }
533
534         /* Allocate memory for driver data */
535         st480 = kzalloc(sizeof(struct st480_data), GFP_KERNEL);
536         if (!st480) {
537                 printk(KERN_ERR "SENODIA st480_probe: memory allocation failed.\n");
538                 err = -ENOMEM;
539                 goto exit1;
540         }
541
542         st480->client = client;
543
544         i2c_set_clientdata(client, st480);
545
546         INIT_DELAYED_WORK(&st480->work, st480_input_func);
547
548         st480->pdata = kmalloc(sizeof(*st480->pdata), GFP_KERNEL);
549         if (st480->pdata == NULL) {
550                 err = -ENOMEM;
551                 dev_err(&client->dev, "failed to allocate memory for pdata: %d\n", err);
552                 goto exit2;
553         }
554
555         memcpy(st480->pdata, client->dev.platform_data, sizeof(*st480->pdata));
556
557
558         if(st480_setup(st480->client) != 0) {
559                 printk("st480 setup error!\n");
560                 goto exit2;
561         }
562
563         /* Declare input device */
564         st480->input_dev = input_allocate_device();
565         if (!st480->input_dev) {
566                 err = -ENOMEM;
567                 printk(KERN_ERR
568                        "SENODIA st480_probe: Failed to allocate input device\n");
569                 goto exit3;
570         }
571
572         /* Setup input device */
573         set_bit(EV_ABS, st480->input_dev->evbit);
574
575         /* x-axis of raw magnetic vector (-32768, 32767) */
576         input_set_abs_params(st480->input_dev, ABS_RX, ABSMIN_MAG, ABSMAX_MAG, 0, 0);
577         /* y-axis of raw magnetic vector (-32768, 32767) */
578         input_set_abs_params(st480->input_dev, ABS_RY, ABSMIN_MAG, ABSMAX_MAG, 0, 0);
579         /* z-axis of raw magnetic vector (-32768, 32767) */
580         input_set_abs_params(st480->input_dev, ABS_RZ, ABSMIN_MAG, ABSMAX_MAG, 0, 0);
581         /* Set name */
582         st480->input_dev->name = "compass";
583
584         /* Register */
585         err = input_register_device(st480->input_dev);
586         if (err) {
587                 printk(KERN_ERR
588                        "SENODIA st480_probe: Unable to register input device\n");
589                 goto exit4;
590         }
591
592         err = misc_register(&st480_device);
593         if (err) {
594                 printk(KERN_ERR
595                        "SENODIA st480_probe: st480_device register failed\n");
596                 goto exit5;
597         }
598
599         /* As default, report all information */
600         atomic_set(&m_flag, 1);
601         atomic_set(&mv_flag, 1);
602
603 #if ST480_AUTO_TEST
604         thread=kthread_run(auto_test_read,NULL,"st480_read_test");
605 #endif
606
607         printk("st480 probe done.");
608         return 0;
609
610 exit5:
611         misc_deregister(&st480_device);
612         input_unregister_device(st480->input_dev);
613 exit4:
614         input_free_device(st480->input_dev);
615 exit3:
616 exit2:
617         kfree(st480);
618 exit1:
619 exit0:
620 exit_alloc_platform_data_failed:
621         return err;
622
623 }
624
625 static int st480_remove(struct i2c_client *client)
626 {
627         misc_deregister(&st480_device);
628         input_unregister_device(st480->input_dev);
629         input_free_device(st480->input_dev);
630         cancel_delayed_work(&st480->work);
631         kfree(st480);
632         return 0;
633 }
634
635 static const struct i2c_device_id st480_id[] = {
636         {ST480_I2C_NAME, 0 },
637         { }
638 };
639
640 static const struct of_device_id st480_of_match[] = {
641        { .compatible = "ST,st480", },
642        { }
643 };
644 MODULE_DEVICE_TABLE(of, st480_of_match);
645 static struct i2c_driver st480_driver = {
646         .probe          = st480_probe,
647         .remove         = st480_remove,
648         .id_table       = st480_id,
649         .driver = {
650                 .name = ST480_I2C_NAME,
651                  .of_match_table = st480_of_match,
652         },
653 };
654
655 static int __init st480_init(void)
656 {
657         return i2c_add_driver(&st480_driver);
658 }
659
660 static void __exit st480_exit(void)
661 {
662         i2c_del_driver(&st480_driver);
663 }
664
665 module_init(st480_init);
666 module_exit(st480_exit);
667
668 MODULE_AUTHOR("Tori Xu <xuezhi_xu@senodia.com>");
669 MODULE_DESCRIPTION("senodia st480 linux driver");
670 MODULE_LICENSE("GPL");
671 MODULE_VERSION("9.0");