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