42636485fa47b21749c33a62e5054510c303dd90
[firefly-linux-kernel-4.4.55.git] / drivers / input / sensors / compass / ak09911.c
1 /* drivers/input/sensors/access/akm09911.c\r
2  *\r
3  * Copyright (C) 2012-2015 ROCKCHIP.\r
4  * Author: luowei <lw@rock-chips.com>\r
5  *\r
6  * This software is licensed under the terms of the GNU General Public\r
7  * License version 2, as published by the Free Software Foundation, and\r
8  * may be copied, distributed, and modified under those terms.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  */\r
16 #include <linux/interrupt.h>\r
17 #include <linux/i2c.h>\r
18 #include <linux/slab.h>\r
19 #include <linux/irq.h>\r
20 #include <linux/miscdevice.h>\r
21 #include <linux/gpio.h>\r
22 #include <asm/uaccess.h>\r
23 #include <asm/atomic.h>\r
24 #include <linux/delay.h>\r
25 #include <linux/input.h>\r
26 #include <linux/workqueue.h>\r
27 #include <linux/freezer.h>\r
28 #include <mach/gpio.h>\r
29 #include <mach/board.h> \r
30 #ifdef CONFIG_HAS_EARLYSUSPEND\r
31 #include <linux/earlysuspend.h>\r
32 #endif\r
33 #include <linux/sensor-dev.h>\r
34 \r
35 \r
36 \r
37 #define SENSOR_DATA_SIZE        9\r
38 #define YPR_DATA_SIZE           16\r
39 #define RWBUF_SIZE              16\r
40 \r
41 #define ACC_DATA_FLAG           0\r
42 #define MAG_DATA_FLAG           1\r
43 #define ORI_DATA_FLAG           2\r
44 #define AKM_NUM_SENSORS         3\r
45 \r
46 #define ACC_DATA_READY          (1<<(ACC_DATA_FLAG))\r
47 #define MAG_DATA_READY          (1<<(MAG_DATA_FLAG))\r
48 #define ORI_DATA_READY          (1<<(ORI_DATA_FLAG))\r
49 \r
50 /*Constant definitions of the AK09911.*/\r
51 #define AK09911_MEASUREMENT_TIME_US     10000\r
52 \r
53 #define AK09911_MODE_SNG_MEASURE        0x01\r
54 #define AK09911_MODE_SELF_TEST          0x10\r
55 #define AK09911_MODE_FUSE_ACCESS        0x1F\r
56 #define AK09911_MODE_POWERDOWN          0x00\r
57 #define AK09911_RESET_DATA              0x01\r
58 \r
59 \r
60 /* Device specific constant values */\r
61 #define AK09911_REG_WIA1                        0x00\r
62 #define AK09911_REG_WIA2                        0x01\r
63 #define AK09911_REG_INFO1                       0x02\r
64 #define AK09911_REG_INFO2                       0x03\r
65 #define AK09911_REG_ST1                         0x10\r
66 #define AK09911_REG_HXL                         0x11\r
67 #define AK09911_REG_HXH                         0x12\r
68 #define AK09911_REG_HYL                         0x13\r
69 #define AK09911_REG_HYH                         0x14\r
70 #define AK09911_REG_HZL                         0x15\r
71 #define AK09911_REG_HZH                         0x16\r
72 #define AK09911_REG_TMPS                        0x17\r
73 #define AK09911_REG_ST2                         0x18\r
74 #define AK09911_REG_CNTL1                       0x30\r
75 #define AK09911_REG_CNTL2                       0x31\r
76 #define AK09911_REG_CNTL3                       0x32\r
77 \r
78 \r
79 #define AK09911_FUSE_ASAX                       0x60\r
80 #define AK09911_FUSE_ASAY                       0x61\r
81 #define AK09911_FUSE_ASAZ                       0x62\r
82 \r
83 #define AK09911_INFO_SIZE                       2\r
84 #define AK09911_CONF_SIZE                       3\r
85 \r
86 \r
87 \r
88 #define COMPASS_IOCTL_MAGIC                   'c'\r
89 \r
90 /* IOCTLs for AKM library */\r
91 #define ECS_IOCTL_WRITE                 _IOW(COMPASS_IOCTL_MAGIC, 0x01, char*)\r
92 #define ECS_IOCTL_READ                  _IOWR(COMPASS_IOCTL_MAGIC, 0x02, char*)\r
93 #define ECS_IOCTL_RESET                 _IO(COMPASS_IOCTL_MAGIC, 0x03) /* NOT used in AK8975 */\r
94 #define ECS_IOCTL_SET_MODE              _IOW(COMPASS_IOCTL_MAGIC, 0x04, short)\r
95 #define ECS_IOCTL_GETDATA               _IOR(COMPASS_IOCTL_MAGIC, 0x05, char[8])\r
96 #define ECS_IOCTL_SET_YPR               _IOW(COMPASS_IOCTL_MAGIC, 0x06, short[12])\r
97 #define ECS_IOCTL_GET_OPEN_STATUS       _IOR(COMPASS_IOCTL_MAGIC, 0x07, int)\r
98 #define ECS_IOCTL_GET_CLOSE_STATUS      _IOR(COMPASS_IOCTL_MAGIC, 0x08, int)\r
99 #define ECS_IOCTL_GET_LAYOUT            _IOR(COMPASS_IOCTL_MAGIC, 0x09, char)\r
100 #define ECS_IOCTL_GET_ACCEL             _IOR(COMPASS_IOCTL_MAGIC, 0x0A, short[3])\r
101 #define ECS_IOCTL_GET_OUTBIT            _IOR(COMPASS_IOCTL_MAGIC, 0x0B, char)\r
102 #define ECS_IOCTL_GET_INFO              _IOR(COMPASS_IOCTL_MAGIC, 0x0C, short)\r
103 #define ECS_IOCTL_GET_CONF              _IOR(COMPASS_IOCTL_MAGIC, 0x0D, short)\r
104 #define ECS_IOCTL_GET_PLATFORM_DATA     _IOR(COMPASS_IOCTL_MAGIC, 0x0E, struct akm_platform_data)\r
105 #define ECS_IOCTL_GET_DELAY             _IOR(COMPASS_IOCTL_MAGIC, 0x30, short)\r
106 \r
107 \r
108 \r
109 #define AK09911_DEVICE_ID               0x05\r
110 static struct i2c_client *this_client;\r
111 static struct miscdevice compass_dev_device;\r
112 \r
113 static short g_akm_rbuf[12];\r
114 static char g_sensor_info[AK09911_INFO_SIZE];\r
115 static char g_sensor_conf[AK09911_CONF_SIZE];\r
116 \r
117 \r
118 /****************operate according to sensor chip:start************/\r
119 \r
120 static int sensor_active(struct i2c_client *client, int enable, int rate)\r
121 {\r
122         struct sensor_private_data *sensor =\r
123             (struct sensor_private_data *) i2c_get_clientdata(client);  \r
124         int result = 0;\r
125                 \r
126         //sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);\r
127         \r
128         //register setting according to chip datasheet          \r
129         if(enable)\r
130         {       \r
131                 sensor->ops->ctrl_data = AK09911_MODE_SNG_MEASURE;      \r
132         }\r
133         else\r
134         {\r
135                 sensor->ops->ctrl_data = AK09911_MODE_POWERDOWN;\r
136         }\r
137 \r
138         DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);\r
139         result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);\r
140         if(result)\r
141                 printk("%s:fail to active sensor\n",__func__);\r
142         \r
143         return result;\r
144 \r
145 }\r
146 \r
147 static int sensor_init(struct i2c_client *client)\r
148 {       \r
149         struct sensor_private_data *sensor =\r
150             (struct sensor_private_data *) i2c_get_clientdata(client);  \r
151         int result = 0;\r
152 \r
153         this_client = client;   \r
154 \r
155         result = sensor->ops->active(client,0,0);\r
156         if(result)\r
157         {\r
158                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
159                 return result;\r
160         }\r
161         \r
162         sensor->status_cur = SENSOR_OFF;\r
163 \r
164         result = misc_register(&compass_dev_device);\r
165         if (result < 0) {\r
166                 printk("%s:fail to register misc device %s\n", __func__, compass_dev_device.name);\r
167                 result = -1;\r
168         }\r
169 \r
170         g_sensor_info[0] = AK09911_REG_WIA1;\r
171         result = sensor_rx_data(client, g_sensor_info, AK09911_INFO_SIZE);\r
172         if(result)\r
173         {\r
174                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
175                 return result;\r
176         }\r
177 \r
178         \r
179         g_sensor_conf[0] = AK09911_FUSE_ASAX;\r
180         result = sensor_rx_data(client, g_sensor_conf, AK09911_CONF_SIZE);\r
181         if(result)\r
182         {\r
183                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
184                 return result;\r
185         }\r
186         \r
187         DBG("%s:status_cur=%d\n",__func__, sensor->status_cur);\r
188         return result;\r
189 }\r
190 \r
191 static int sensor_report_value(struct i2c_client *client)\r
192 {\r
193         struct sensor_private_data *sensor =\r
194                 (struct sensor_private_data *) i2c_get_clientdata(client);      \r
195         char buffer[SENSOR_DATA_SIZE] = {0};    \r
196         unsigned char *stat;\r
197         unsigned char *stat2;   \r
198         int ret = 0;    \r
199         char value = 0;\r
200         int i;\r
201 \r
202         if(sensor->ops->read_len < SENSOR_DATA_SIZE)    //sensor->ops->read_len = 8\r
203         {\r
204                 printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);\r
205                 return -1;\r
206         }\r
207         \r
208         memset(buffer, 0, SENSOR_DATA_SIZE);\r
209         \r
210         /* Data bytes from hardware xL, xH, yL, yH, zL, zH */   \r
211         do {\r
212                 *buffer = sensor->ops->read_reg;\r
213                 ret = sensor_rx_data(client, buffer, sensor->ops->read_len);\r
214                 if (ret < 0)\r
215                 return ret;\r
216         } while (0);\r
217 \r
218         stat = &buffer[0];\r
219         stat2 = &buffer[7];\r
220         \r
221         /*\r
222          * ST : data ready -
223          * Measurement has been completed and data is ready to be read.
224          */\r
225         if ((*stat & 0x01) != 0x01) {\r
226                 DBG(KERN_ERR "%s:ST is not set\n",__func__);\r
227                 return -1;\r
228         }\r
229 #if 0\r
230         /*
231          * ST2 : data error -
232          * occurs when data read is started outside of a readable period;
233          * data read would not be correct.
234          * Valid in continuous measurement mode only.
235          * In single measurement mode this error should not occour but we
236          * stil account for it and return an error, since the data would be
237          * corrupted.
238          * DERR bit is self-clearing when ST2 register is read.
239          */
240         if (*stat2 & 0x04)\r
241         {\r
242                 DBG(KERN_ERR "%s:compass data error\n",__func__);\r
243                 return -2;\r
244         }\r
245         \r
246         /*
247          * ST2 : overflow -
248          * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
249          * This is likely to happen in presence of an external magnetic
250          * disturbance; it indicates, the sensor data is incorrect and should
251          * be ignored.
252          * An error is returned.
253          * HOFL bit clears when a new measurement starts.
254          */
255         if (*stat2 & 0x08)\r
256         {       \r
257                 DBG(KERN_ERR "%s:compass data overflow\n",__func__);\r
258                 return -3;\r
259         }\r
260 #endif\r
261         /* »¥³âµØ»º´æÊý¾Ý. */\r
262         mutex_lock(&sensor->data_mutex);        \r
263         memcpy(sensor->sensor_data, buffer, sensor->ops->read_len);\r
264         mutex_unlock(&sensor->data_mutex);\r
265         DBG("%s:",__func__);\r
266         for(i=0; i<sensor->ops->read_len; i++)\r
267                 DBG("0x%x,",buffer[i]);\r
268         DBG("\n");\r
269 \r
270         if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0))    //read sensor intterupt status register\r
271         {\r
272                 \r
273                 value = sensor_read_reg(client, sensor->ops->int_status_reg);\r
274                 DBG("%s:sensor int status :0x%x\n",__func__,value);\r
275         }\r
276 \r
277         \r
278         //trigger next measurement \r
279         ret = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);\r
280         if(ret)\r
281         {\r
282                 printk(KERN_ERR "%s:fail to set ctrl_data:0x%x\n",__func__,sensor->ops->ctrl_data);\r
283                 return ret;\r
284         }\r
285 \r
286         return ret;\r
287 }\r
288 \r
289 static void compass_set_YPR(int *rbuf)\r
290 {\r
291         struct sensor_private_data *sensor =\r
292             (struct sensor_private_data *) i2c_get_clientdata(this_client);     \r
293 \r
294         /* No events are reported */\r
295         if (!rbuf[0]) {\r
296                 printk("%s:Don't waste a time.",__func__);\r
297                 return;\r
298         }\r
299 \r
300         DBG("%s:buf[0]=0x%x\n",__func__, rbuf[0]);\r
301         \r
302         /* Report magnetic sensor information */\r
303         if (atomic_read(&sensor->flags.m_flag) && (rbuf[0] & ORI_DATA_READY)) {\r
304                 input_report_abs(sensor->input_dev, ABS_RX, rbuf[9]);\r
305                 input_report_abs(sensor->input_dev, ABS_RY, rbuf[10]);\r
306                 input_report_abs(sensor->input_dev, ABS_RZ, rbuf[11]);\r
307                 input_report_abs(sensor->input_dev, ABS_RUDDER, rbuf[4]);\r
308                 DBG("%s:m_flag:x=%d,y=%d,z=%d,RUDDER=%d\n",__func__,rbuf[9], rbuf[10], rbuf[11], rbuf[4]);\r
309         }\r
310         \r
311         /* Report acceleration sensor information */\r
312         if (atomic_read(&sensor->flags.a_flag) && (rbuf[0] & ACC_DATA_READY)) {\r
313                 input_report_abs(sensor->input_dev, ABS_X, rbuf[1]);\r
314                 input_report_abs(sensor->input_dev, ABS_Y, rbuf[2]);\r
315                 input_report_abs(sensor->input_dev, ABS_Z, rbuf[3]);\r
316                 input_report_abs(sensor->input_dev, ABS_WHEEL, rbuf[4]);\r
317                 \r
318                 DBG("%s:a_flag:x=%d,y=%d,z=%d,WHEEL=%d\n",__func__,rbuf[1], rbuf[2], rbuf[3], rbuf[4]);\r
319         }\r
320         \r
321         /* Report magnetic vector information */\r
322         if (atomic_read(&sensor->flags.mv_flag) && (rbuf[0] & MAG_DATA_READY)) {\r
323                 input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[5]);\r
324                 input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[6]);\r
325                 input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[7]);        \r
326                 input_report_abs(sensor->input_dev, ABS_HAT1X, rbuf[8]);\r
327         \r
328                 DBG("%s:mv_flag:x=%d,y=%d,z=%d,status=%d\n",__func__,rbuf[5], rbuf[6], rbuf[7], rbuf[8]);\r
329         }\r
330         \r
331         input_sync(sensor->input_dev);\r
332 \r
333         memcpy(g_akm_rbuf, rbuf, 12);   //used for ECS_IOCTL_GET_ACCEL\r
334 }\r
335 \r
336 \r
337 \r
338 static int compass_dev_open(struct inode *inode, struct file *file)\r
339 {\r
340         struct sensor_private_data* sensor = \r
341                 (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
342         int result = 0;\r
343         DBG("%s\n",__func__);\r
344 \r
345         return result;\r
346 }\r
347 \r
348 \r
349 static int compass_dev_release(struct inode *inode, struct file *file)\r
350 {\r
351         struct sensor_private_data* sensor = \r
352                 (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
353         int result = 0; \r
354         DBG("%s\n",__func__);\r
355 \r
356         return result;\r
357 }\r
358 \r
359 static int compass_akm_set_mode(struct i2c_client *client, char mode)\r
360 {\r
361         struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
362         int result = 0; \r
363 \r
364         switch(mode & 0x1f)\r
365         {\r
366                 case AK09911_MODE_SNG_MEASURE:\r
367                 case AK09911_MODE_SELF_TEST:    \r
368                 case AK09911_MODE_FUSE_ACCESS:                  \r
369                         if(sensor->status_cur == SENSOR_OFF)\r
370                         {\r
371                                 if(sensor->pdata->irq_enable)\r
372                                 {\r
373                                         //DBG("%s:enable irq=%d\n",__func__,client->irq);\r
374                                         //enable_irq(client->irq);\r
375                                 }       \r
376                                 else\r
377                                 {\r
378                                         schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms));\r
379                                 }\r
380                                 \r
381                                 sensor->status_cur = SENSOR_ON;\r
382                         }\r
383 \r
384                         break;\r
385 \r
386                 case AK09911_MODE_POWERDOWN:    \r
387                         if(sensor->status_cur == SENSOR_ON)\r
388                         {\r
389                                 if(sensor->pdata->irq_enable)\r
390                                 {       \r
391                                         //DBG("%s:disable irq=%d\n",__func__,client->irq);\r
392                                         //disable_irq_nosync(client->irq);//disable irq\r
393                                 }\r
394                                 else\r
395                                 cancel_delayed_work_sync(&sensor->delaywork);   \r
396 \r
397                                 sensor->status_cur = SENSOR_OFF;\r
398                         }\r
399                         break;\r
400 \r
401         }\r
402         \r
403         switch(mode & 0x1f)\r
404         {\r
405                 case AK09911_MODE_SNG_MEASURE:          \r
406                         result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK09911_MODE_SNG_MEASURE);\r
407                         if(result)\r
408                         printk("%s:i2c error,mode=%d\n",__func__,mode);                         \r
409                         break;\r
410                 case AK09911_MODE_SELF_TEST:                    \r
411                         result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK09911_MODE_SELF_TEST);\r
412                         if(result)\r
413                         printk("%s:i2c error,mode=%d\n",__func__,mode);\r
414                         break;\r
415                 case AK09911_MODE_FUSE_ACCESS:\r
416                         result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK09911_MODE_FUSE_ACCESS);\r
417                         if(result)\r
418                         printk("%s:i2c error,mode=%d\n",__func__,mode);\r
419                         break;\r
420                 case AK09911_MODE_POWERDOWN:\r
421                         /* Set powerdown mode */\r
422                         result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK09911_MODE_POWERDOWN);\r
423                         if(result)\r
424                         printk("%s:i2c error,mode=%d\n",__func__,mode);\r
425                         udelay(100);\r
426                         break;\r
427                 default:\r
428                         printk("%s: Unknown mode(%d)", __func__, mode);\r
429                         result = -EINVAL;\r
430                         break;\r
431         }\r
432         DBG("%s:mode=0x%x\n",__func__,mode);\r
433         return result;\r
434 \r
435 }\r
436 \r
437 static int compass_akm_reset(struct i2c_client *client)\r
438 {\r
439         struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
440         int result = 0; \r
441         \r
442         if(sensor->pdata->reset_pin > 0)\r
443         {\r
444                 gpio_direction_output(sensor->pdata->reset_pin, GPIO_LOW);\r
445                 udelay(10);\r
446                 gpio_direction_output(sensor->pdata->reset_pin, GPIO_HIGH);\r
447         }\r
448         else    \r
449         {\r
450                 /* Set measure mode */\r
451                 result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK09911_MODE_SNG_MEASURE);\r
452                 if(result)\r
453                 printk("%s:fail to Set measure mode\n",__func__);\r
454         }\r
455         \r
456         udelay(100);\r
457         \r
458         return result;\r
459 \r
460 }\r
461 \r
462 \r
463 \r
464 static int compass_akm_get_openstatus(void)\r
465 {       \r
466         struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
467         wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) != 0));\r
468         return atomic_read(&sensor->flags.open_flag);\r
469 }\r
470 \r
471 static int compass_akm_get_closestatus(void)\r
472 {       \r
473         struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
474         wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) <= 0));\r
475         return atomic_read(&sensor->flags.open_flag);\r
476 }\r
477 \r
478 \r
479 /* ioctl - I/O control */\r
480 static long compass_dev_ioctl(struct file *file,\r
481                           unsigned int cmd, unsigned long arg)\r
482 {\r
483     struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client);\r
484         struct i2c_client *client = this_client;\r
485         void __user *argp = (void __user *)arg;\r
486         int result = 0;\r
487         struct akm_platform_data compass;\r
488                 \r
489         /* NOTE: In this function the size of "char" should be 1-byte. */\r
490         char compass_data[SENSOR_DATA_SIZE];    /* for GETDATA */\r
491         char rwbuf[RWBUF_SIZE];                 /* for READ/WRITE */\r
492         char mode;                              /* for SET_MODE*/\r
493         int value[YPR_DATA_SIZE];               /* for SET_YPR */\r
494         int status;                             /* for OPEN/CLOSE_STATUS */\r
495         int ret = -1;                           /* Return value. */\r
496         \r
497         //int8_t sensor_buf[SENSOR_DATA_SIZE];  /* for GETDATA */\r
498         //int32_t ypr_buf[YPR_DATA_SIZE];       /* for SET_YPR */\r
499         int16_t acc_buf[3];                     /* for GET_ACCEL */\r
500         int64_t delay[AKM_NUM_SENSORS];         /* for GET_DELAY */\r
501         char layout;            /* for GET_LAYOUT */\r
502         char outbit;            /* for GET_OUTBIT */\r
503 \r
504         switch (cmd) {\r
505         case ECS_IOCTL_WRITE:\r
506         case ECS_IOCTL_READ:\r
507                 if (argp == NULL) {\r
508                         return -EINVAL;\r
509                 }\r
510                 if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) {\r
511                         return -EFAULT;\r
512                 }\r
513                 break;\r
514         case ECS_IOCTL_SET_MODE:\r
515                 if (argp == NULL) {\r
516                         return -EINVAL;\r
517                 }\r
518                 if (copy_from_user(&mode, argp, sizeof(mode))) {\r
519                         return -EFAULT;\r
520                 }\r
521                 break;\r
522         case ECS_IOCTL_SET_YPR:\r
523                 if (argp == NULL) {\r
524                         return -EINVAL;\r
525                 }\r
526                 if (copy_from_user(&value, argp, sizeof(value))) {\r
527                         return -EFAULT;\r
528                 }\r
529                 break;\r
530         case ECS_IOCTL_GETDATA:\r
531         case ECS_IOCTL_GET_OPEN_STATUS:\r
532         case ECS_IOCTL_GET_CLOSE_STATUS:\r
533         case ECS_IOCTL_GET_DELAY:\r
534         case ECS_IOCTL_GET_LAYOUT:\r
535         case ECS_IOCTL_GET_OUTBIT:\r
536         case ECS_IOCTL_GET_ACCEL:\r
537         case ECS_IOCTL_GET_INFO:\r
538         case ECS_IOCTL_GET_CONF:\r
539                 /* Just check buffer pointer */\r
540                 if (argp == NULL) {\r
541                         printk("%s:invalid argument\n",__func__);\r
542                         return -EINVAL;\r
543                 }\r
544                 break;\r
545         default:\r
546                 break;\r
547         }\r
548 \r
549         switch (cmd) {\r
550         case ECS_IOCTL_WRITE:\r
551                 DBG("%s:ECS_IOCTL_WRITE start\n",__func__);\r
552                 mutex_lock(&sensor->operation_mutex);\r
553                 if ((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) {                    \r
554                         mutex_unlock(&sensor->operation_mutex);\r
555                         return -EINVAL;\r
556                 }\r
557                 ret = sensor_tx_data(client, &rwbuf[1], rwbuf[0]);\r
558                 if (ret < 0) {  \r
559                         mutex_unlock(&sensor->operation_mutex);         \r
560                         printk("%s:fait to tx data\n",__func__);\r
561                         return ret;\r
562                 }                       \r
563                 mutex_unlock(&sensor->operation_mutex);\r
564                 break;\r
565         case ECS_IOCTL_READ:                            \r
566                 DBG("%s:ECS_IOCTL_READ start\n",__func__);\r
567                 mutex_lock(&sensor->operation_mutex);\r
568                 if ((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) {            \r
569                         mutex_unlock(&sensor->operation_mutex);                 \r
570                         printk("%s:data is error\n",__func__);\r
571                         return -EINVAL;\r
572                 }\r
573                 ret = sensor_rx_data(client, &rwbuf[1], rwbuf[0]);\r
574                 if (ret < 0) {  \r
575                         mutex_unlock(&sensor->operation_mutex);         \r
576                         printk("%s:fait to rx data\n",__func__);\r
577                         return ret;\r
578                 }               \r
579                 mutex_unlock(&sensor->operation_mutex);\r
580                 break;\r
581         case ECS_IOCTL_SET_MODE:\r
582                 DBG("%s:ECS_IOCTL_SET_MODE start\n",__func__);          \r
583                 mutex_lock(&sensor->operation_mutex);\r
584                 if(sensor->ops->ctrl_data != mode)\r
585                 {\r
586                         ret = compass_akm_set_mode(client, mode);\r
587                         if (ret < 0) {\r
588                                 printk("%s:fait to set mode\n",__func__);               \r
589                                 mutex_unlock(&sensor->operation_mutex);\r
590                                 return ret;\r
591                         }\r
592                         \r
593                         sensor->ops->ctrl_data = mode;\r
594                 }\r
595                 mutex_unlock(&sensor->operation_mutex);\r
596                 break;\r
597         case ECS_IOCTL_GETDATA:\r
598                         DBG("%s:ECS_IOCTL_GETDATA start\n",__func__);\r
599                         mutex_lock(&sensor->data_mutex);        \r
600                         memcpy(compass_data, sensor->sensor_data, SENSOR_DATA_SIZE);    //get data from buffer\r
601                         mutex_unlock(&sensor->data_mutex);\r
602                         break;\r
603         case ECS_IOCTL_SET_YPR:                 \r
604                         DBG("%s:ECS_IOCTL_SET_YPR start\n",__func__);\r
605                         mutex_lock(&sensor->data_mutex);\r
606                         compass_set_YPR(value);         \r
607                         mutex_unlock(&sensor->data_mutex);\r
608                 break;\r
609         case ECS_IOCTL_GET_OPEN_STATUS:\r
610                 status = compass_akm_get_openstatus();  \r
611                 DBG("%s:openstatus=%d\n",__func__,status);\r
612                 break;\r
613         case ECS_IOCTL_GET_CLOSE_STATUS:\r
614                 status = compass_akm_get_closestatus(); \r
615                 DBG("%s:closestatus=%d\n",__func__,status);\r
616                 break;\r
617         case ECS_IOCTL_GET_DELAY:\r
618                 DBG("%s:ECS_IOCTL_GET_DELAY start\n",__func__);\r
619                 mutex_lock(&sensor->operation_mutex);\r
620                 delay[0] = sensor->flags.delay;\r
621                 delay[1] = sensor->flags.delay;\r
622                 delay[2] = sensor->flags.delay;\r
623                 mutex_unlock(&sensor->operation_mutex);\r
624                 break;\r
625         \r
626         case ECS_IOCTL_GET_PLATFORM_DATA:                       \r
627                 DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__);\r
628                 memcpy(compass.m_layout, sensor->pdata->m_layout, sizeof(sensor->pdata->m_layout));\r
629                 memcpy(compass.project_name, sensor->pdata->project_name, sizeof(sensor->pdata->project_name));\r
630                 ret = copy_to_user(argp, &compass, sizeof(compass));\r
631                 if(ret < 0)\r
632                 {\r
633                         printk("%s:error,ret=%d\n",__FUNCTION__, ret);\r
634                         return ret;\r
635                 }\r
636                 break;\r
637         case ECS_IOCTL_GET_LAYOUT:\r
638                 DBG("%s:ECS_IOCTL_GET_LAYOUT start\n",__func__);\r
639                 if((sensor->pdata->layout >= 1) && (sensor->pdata->layout <=8 ))
640                 layout = sensor->pdata->layout;
641                 else
642                 layout = 1;
643                 break;\r
644         case ECS_IOCTL_GET_OUTBIT:\r
645                 DBG("%s:ECS_IOCTL_GET_OUTBIT start\n",__func__);\r
646                 outbit = 1;     //sensor->pdata->outbit;\r
647                 break;\r
648         case ECS_IOCTL_RESET:\r
649                 DBG("%s:ECS_IOCTL_RESET start\n",__func__);\r
650                 ret = compass_akm_reset(client);\r
651                 if (ret < 0)\r
652                         return ret;\r
653                 break;\r
654         case ECS_IOCTL_GET_ACCEL:\r
655                 DBG("%s:ECS_IOCTL_GET_ACCEL start,no accel data\n",__func__);\r
656                 mutex_lock(&sensor->operation_mutex);\r
657                 acc_buf[0] = g_akm_rbuf[6];\r
658                 acc_buf[1] = g_akm_rbuf[7];\r
659                 acc_buf[2] = g_akm_rbuf[8];\r
660                 mutex_unlock(&sensor->operation_mutex);\r
661                 break;\r
662         case ECS_IOCTL_GET_INFO:\r
663                 ret = copy_to_user(argp, g_sensor_info, sizeof(g_sensor_info));\r
664                 if(ret < 0)\r
665                 {\r
666                         printk("%s:error,ret=%d\n",__FUNCTION__, ret);\r
667                         return ret;\r
668                 }\r
669                 break;\r
670         case ECS_IOCTL_GET_CONF:\r
671                 ret = copy_to_user(argp, g_sensor_conf, sizeof(g_sensor_conf));\r
672                 if(ret < 0)\r
673                 {\r
674                         printk("%s:error,ret=%d\n",__FUNCTION__, ret);\r
675                         return ret;\r
676                 }\r
677                 break;\r
678 \r
679         default:\r
680                 return -ENOTTY;\r
681         }\r
682 \r
683         switch (cmd) {\r
684         case ECS_IOCTL_READ:\r
685                 if (copy_to_user(argp, &rwbuf, rwbuf[0]+1)) {\r
686                         return -EFAULT;\r
687                 }\r
688                 break;\r
689         case ECS_IOCTL_GETDATA:\r
690                 if (copy_to_user(argp, &compass_data, sizeof(compass_data))) {\r
691                         return -EFAULT;\r
692                 }\r
693                 break;\r
694         case ECS_IOCTL_GET_OPEN_STATUS:\r
695         case ECS_IOCTL_GET_CLOSE_STATUS:\r
696                 if (copy_to_user(argp, &status, sizeof(status))) {\r
697                         return -EFAULT;\r
698                 }\r
699                 break;\r
700         case ECS_IOCTL_GET_DELAY:\r
701                 if (copy_to_user(argp, &delay, sizeof(delay))) {\r
702                         return -EFAULT;\r
703                 }\r
704                 break;\r
705         case ECS_IOCTL_GET_LAYOUT:\r
706                 if (copy_to_user(argp, &layout, sizeof(layout))) {\r
707                         printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
708                         return -EFAULT;\r
709                 }\r
710                 break;\r
711         case ECS_IOCTL_GET_OUTBIT:\r
712                 if (copy_to_user(argp, &outbit, sizeof(outbit))) {\r
713                         printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
714                         return -EFAULT;\r
715                 }\r
716                 break;\r
717         case ECS_IOCTL_GET_ACCEL:\r
718                 if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) {\r
719                         printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
720                         return -EFAULT;\r
721                 }\r
722                 break;\r
723         default:\r
724                 break;\r
725         }\r
726 \r
727         return result;\r
728 }\r
729 \r
730 static struct file_operations compass_dev_fops =\r
731 {\r
732         .owner = THIS_MODULE,\r
733         .open = compass_dev_open,\r
734         .release = compass_dev_release, \r
735         .unlocked_ioctl = compass_dev_ioctl,\r
736 };\r
737 \r
738 \r
739 static struct miscdevice compass_dev_device =\r
740 {       \r
741         .minor = MISC_DYNAMIC_MINOR,\r
742         .name = "akm_dev",\r
743         .fops = &compass_dev_fops,\r
744 };\r
745 \r
746 struct sensor_operate compass_akm09911_ops = {\r
747         .name                           = "akm09911",\r
748         .type                           = SENSOR_TYPE_COMPASS,  //it is important\r
749         .id_i2c                         = COMPASS_ID_AK09911,\r
750         .read_reg                       = AK09911_REG_ST1,      //read data\r
751         .read_len                       = SENSOR_DATA_SIZE,     //data length\r
752         .id_reg                         = AK09911_REG_WIA2,     //read id\r
753         .id_data                        = AK09911_DEVICE_ID,\r
754         .precision                      = 8,                    //12 bits\r
755         .ctrl_reg                       = AK09911_REG_CNTL2,    //enable or disable \r
756         .int_status_reg                 = SENSOR_UNKNOW_DATA,   //not exist\r
757         .range                          = {-0xffff,0xffff},\r
758         .trig                           = IRQF_TRIGGER_RISING,  //if LEVEL interrupt then IRQF_ONESHOT\r
759         .active                         = sensor_active,        \r
760         .init                           = sensor_init,\r
761         .report                         = sensor_report_value,  \r
762         .misc_dev                       = NULL,                 //private misc support\r
763 };\r
764 \r
765 /****************operate according to sensor chip:end************/\r
766 \r
767 //function name should not be changed\r
768 static struct sensor_operate *compass_get_ops(void)\r
769 {\r
770         return &compass_akm09911_ops; \r
771 }\r
772 \r
773 \r
774 static int __init compass_akm09911_init(void)\r
775 {\r
776         struct sensor_operate *ops = compass_get_ops();\r
777         int result = 0;\r
778         int type = ops->type;\r
779         result = sensor_register_slave(type, NULL, NULL, compass_get_ops);\r
780                                 \r
781         return result;\r
782 }\r
783 \r
784 static void __exit compass_akm09911_exit(void)\r
785 {\r
786         struct sensor_operate *ops = compass_get_ops();\r
787         int type = ops->type;\r
788         sensor_unregister_slave(type, NULL, NULL, compass_get_ops);\r
789 }\r
790 \r
791 \r
792 module_init(compass_akm09911_init);\r
793 module_exit(compass_akm09911_exit);\r
794 \r
795 \r