--- /dev/null
+/* drivers/input/sensors/access/akm8963.c\r
+ *\r
+ * Copyright (C) 2012-2015 ROCKCHIP.\r
+ * Author: luowei <lw@rock-chips.com>\r
+ *\r
+ * This software is licensed under the terms of the GNU General Public\r
+ * License version 2, as published by the Free Software Foundation, and\r
+ * may be copied, distributed, and modified under those terms.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ */\r
+#include <linux/interrupt.h>\r
+#include <linux/i2c.h>\r
+#include <linux/slab.h>\r
+#include <linux/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/gpio.h>\r
+#include <asm/uaccess.h>\r
+#include <asm/atomic.h>\r
+#include <linux/delay.h>\r
+#include <linux/input.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/freezer.h>\r
+#include <mach/gpio.h>\r
+#include <mach/board.h> \r
+#ifdef CONFIG_HAS_EARLYSUSPEND\r
+#include <linux/earlysuspend.h>\r
+#endif\r
+#include <linux/sensor-dev.h>\r
+\r
+#define SENSOR_DATA_SIZE 8\r
+\r
+#if 0\r
+#define SENSOR_DEBUG_TYPE SENSOR_TYPE_COMPASS\r
+#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define SENSOR_DATA_SIZE 8\r
+#define YPR_DATA_SIZE 12\r
+#define RWBUF_SIZE 16\r
+\r
+#define ACC_DATA_FLAG 0\r
+#define MAG_DATA_FLAG 1\r
+#define ORI_DATA_FLAG 2\r
+#define AKM_NUM_SENSORS 3\r
+\r
+#define ACC_DATA_READY (1<<(ACC_DATA_FLAG))\r
+#define MAG_DATA_READY (1<<(MAG_DATA_FLAG))\r
+#define ORI_DATA_READY (1<<(ORI_DATA_FLAG))\r
+\r
+/*! \name AK8963 constant definition\r
+ \anchor AK8963_Def\r
+ Constant definitions of the AK8963.*/\r
+#define AK8963_MEASUREMENT_TIME_US 10000\r
+\r
+/*! \name AK8963 operation mode\r
+ \anchor AK8963_Mode\r
+ Defines an operation mode of the AK8963.*/\r
+/*! @{*/\r
+#define AK8963_MODE_SNG_MEASURE 0x01\r
+#define AK8963_MODE_SELF_TEST 0x08\r
+#define AK8963_MODE_FUSE_ACCESS 0x0F\r
+#define AK8963_MODE_POWERDOWN 0x00\r
+\r
+/*! @}*/\r
+\r
+/*! \name AK8963 register address\r
+\anchor AK8963_REG\r
+Defines a register address of the AK8963.*/\r
+/*! @{*/\r
+#define AK8963_REG_WIA 0x00\r
+#define AK8963_REG_INFO 0x01\r
+#define AK8963_REG_ST1 0x02\r
+#define AK8963_REG_HXL 0x03\r
+#define AK8963_REG_HXH 0x04\r
+#define AK8963_REG_HYL 0x05\r
+#define AK8963_REG_HYH 0x06\r
+#define AK8963_REG_HZL 0x07\r
+#define AK8963_REG_HZH 0x08\r
+#define AK8963_REG_ST2 0x09\r
+#define AK8963_REG_CNTL1 0x0A\r
+#define AK8963_REG_CNTL2 0x0B\r
+#define AK8963_REG_ASTC 0x0C\r
+#define AK8963_REG_TS1 0x0D\r
+#define AK8963_REG_TS2 0x0E\r
+#define AK8963_REG_I2CDIS 0x0F\r
+/*! @}*/\r
+\r
+/*! \name AK8963 fuse-rom address\r
+\anchor AK8963_FUSE\r
+Defines a read-only address of the fuse ROM of the AK8963.*/\r
+/*! @{*/\r
+#define AK8963_FUSE_ASAX 0x10\r
+#define AK8963_FUSE_ASAY 0x11\r
+#define AK8963_FUSE_ASAZ 0x12\r
+/*! @}*/\r
+\r
+#define AK8963_INFO_DATA (0x03<<3)\r
+\r
+\r
+#define COMPASS_IOCTL_MAGIC 'c'\r
+\r
+/* IOCTLs for AKM library */\r
+#define ECS_IOCTL_WRITE _IOW(COMPASS_IOCTL_MAGIC, 0x01, char*)\r
+#define ECS_IOCTL_READ _IOWR(COMPASS_IOCTL_MAGIC, 0x02, char*)\r
+#define ECS_IOCTL_RESET _IO(COMPASS_IOCTL_MAGIC, 0x03) /* NOT used in AK8975 */\r
+#define ECS_IOCTL_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x04, short)\r
+#define ECS_IOCTL_GETDATA _IOR(COMPASS_IOCTL_MAGIC, 0x05, char[SENSOR_DATA_SIZE])\r
+#define ECS_IOCTL_SET_YPR _IOW(COMPASS_IOCTL_MAGIC, 0x06, short[12])\r
+#define ECS_IOCTL_GET_OPEN_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x07, int)\r
+#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x08, int)\r
+#define ECS_IOCTL_GET_LAYOUT _IOR(COMPASS_IOCTL_MAGIC, 0x09, char)\r
+#define ECS_IOCTL_GET_ACCEL _IOR(COMPASS_IOCTL_MAGIC, 0x0A, short[3])\r
+#define ECS_IOCTL_GET_OUTBIT _IOR(COMPASS_IOCTL_MAGIC, 0x0B, char)\r
+#define ECS_IOCTL_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x30, short)\r
+#define ECS_IOCTL_GET_PROJECT_NAME _IOR(COMPASS_IOCTL_MAGIC, 0x0D, char[64])\r
+#define ECS_IOCTL_GET_MATRIX _IOR(COMPASS_IOCTL_MAGIC, 0x0E, short [4][3][3])\r
+#define ECS_IOCTL_GET_PLATFORM_DATA _IOR(COMPASS_IOCTL_MAGIC, 0x0E, struct akm_platform_data)\r
+\r
+\r
+\r
+#define AK8963_DEVICE_ID 0x48\r
+static struct i2c_client *this_client;\r
+\r
+static short g_akm_rbuf[12];\r
+\r
+\r
+/****************operate according to sensor chip:start************/\r
+\r
+static int sensor_active(struct i2c_client *client, int enable, int rate)\r
+{\r
+ struct sensor_private_data *sensor =\r
+ (struct sensor_private_data *) i2c_get_clientdata(client); \r
+ int result = 0;\r
+ \r
+ //sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);\r
+ \r
+ //register setting according to chip datasheet \r
+ if(enable)\r
+ { \r
+ sensor->ops->ctrl_data = AK8963_MODE_SNG_MEASURE; \r
+ }\r
+ else\r
+ {\r
+ sensor->ops->ctrl_data = AK8963_MODE_POWERDOWN;\r
+ }\r
+\r
+ DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable);\r
+ result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);\r
+ if(result)\r
+ printk("%s:fail to active sensor\n",__func__);\r
+ \r
+ return result;\r
+\r
+}\r
+\r
+static int sensor_init(struct i2c_client *client)\r
+{ \r
+ struct sensor_private_data *sensor =\r
+ (struct sensor_private_data *) i2c_get_clientdata(client); \r
+ int result = 0;\r
+ char info = 0;\r
+\r
+ this_client = client; \r
+\r
+ result = sensor->ops->active(client,0,0);\r
+ if(result)\r
+ {\r
+ printk("%s:line=%d,error\n",__func__,__LINE__);\r
+ return result;\r
+ }\r
+ \r
+ sensor->status_cur = SENSOR_OFF;\r
+\r
+ info = sensor_read_reg(client, AK8963_REG_INFO); \r
+ if((info & (0x0f<<3)) != AK8963_INFO_DATA)\r
+ {\r
+ printk("%s:info=0x%x,it is not %s\n",__func__, info, sensor->ops->name);\r
+ result = -1;\r
+ }\r
+\r
+ DBG("%s:status_cur=%d\n",__func__, sensor->status_cur);\r
+ return result;\r
+}\r
+\r
+static int sensor_report_value(struct i2c_client *client)\r
+{\r
+ struct sensor_private_data *sensor =\r
+ (struct sensor_private_data *) i2c_get_clientdata(client); \r
+ char buffer[8] = {0}; \r
+ unsigned char *stat;\r
+ unsigned char *stat2; \r
+ int ret = 0; \r
+ char value = 0;\r
+#ifdef SENSOR_DEBUG_TYPE \r
+ int i;\r
+#endif \r
+ if(sensor->ops->read_len < 8) //sensor->ops->read_len = 8\r
+ {\r
+ printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);\r
+ return -1;\r
+ }\r
+ \r
+ memset(buffer, 0, 8);\r
+ \r
+ /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ \r
+ do {\r
+ *buffer = sensor->ops->read_reg;\r
+ ret = sensor_rx_data(client, buffer, sensor->ops->read_len);\r
+ if (ret < 0)\r
+ return ret;\r
+ } while (0);\r
+\r
+ stat = &buffer[0];\r
+ stat2 = &buffer[7];\r
+ \r
+ /*\r
+ * ST : data ready -
+ * Measurement has been completed and data is ready to be read.
+ */\r
+ if ((*stat & 0x01) != 0x01) {\r
+ DBG(KERN_ERR "%s:ST is not set\n",__func__);\r
+ return -1;\r
+ }\r
+
+ /*
+ * ST2 : data error -
+ * occurs when data read is started outside of a readable period;
+ * data read would not be correct.
+ * Valid in continuous measurement mode only.
+ * In single measurement mode this error should not occour but we
+ * stil account for it and return an error, since the data would be
+ * corrupted.
+ * DERR bit is self-clearing when ST2 register is read.
+ */
+ if (*stat2 & 0x04)\r
+ {\r
+ DBG(KERN_ERR "%s:compass data error\n",__func__);\r
+ return -2;\r
+ }\r
+ \r
+ /*
+ * ST2 : overflow -
+ * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
+ * This is likely to happen in presence of an external magnetic
+ * disturbance; it indicates, the sensor data is incorrect and should
+ * be ignored.
+ * An error is returned.
+ * HOFL bit clears when a new measurement starts.
+ */
+ if (*stat2 & 0x08)\r
+ { \r
+ DBG(KERN_ERR "%s:compass data overflow\n",__func__);\r
+ return -3;\r
+ }\r
+ \r
+ /* »¥³âµØ»º´æÊý¾Ý. */\r
+ mutex_lock(&sensor->data_mutex); \r
+ memcpy(sensor->sensor_data, buffer, sensor->ops->read_len);\r
+ mutex_unlock(&sensor->data_mutex);\r
+#ifdef SENSOR_DEBUG_TYPE \r
+ DBG("%s:",__func__);\r
+ for(i=0; i<sensor->ops->read_len; i++)\r
+ DBG("0x%x,",buffer[i]);\r
+ DBG("\n");\r
+#endif \r
+\r
+ if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register\r
+ {\r
+ \r
+ value = sensor_read_reg(client, sensor->ops->int_status_reg);\r
+ DBG("%s:sensor int status :0x%x\n",__func__,value);\r
+ }\r
+\r
+ \r
+ //trigger next measurement \r
+ ret = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);\r
+ if(ret)\r
+ {\r
+ printk(KERN_ERR "%s:fail to set ctrl_data:0x%x\n",__func__,sensor->ops->ctrl_data);\r
+ return ret;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static void compass_set_YPR(int *rbuf)\r
+{\r
+ struct sensor_private_data *sensor =\r
+ (struct sensor_private_data *) i2c_get_clientdata(this_client); \r
+\r
+ /* No events are reported */\r
+ if (!rbuf[0]) {\r
+ printk("%s:Don't waste a time.",__func__);\r
+ return;\r
+ }\r
+\r
+ DBG("%s:buf[0]=0x%x\n",__func__, rbuf[0]);\r
+ \r
+ /* Report magnetic sensor information */\r
+ if (atomic_read(&sensor->flags.m_flag) && (rbuf[0] & ORI_DATA_READY)) {\r
+ input_report_abs(sensor->input_dev, ABS_RX, rbuf[9]);\r
+ input_report_abs(sensor->input_dev, ABS_RY, rbuf[10]);\r
+ input_report_abs(sensor->input_dev, ABS_RZ, rbuf[11]);\r
+ input_report_abs(sensor->input_dev, ABS_RUDDER, rbuf[4]);\r
+ DBG("%s:m_flag:x=%d,y=%d,z=%d,RUDDER=%d\n",__func__,rbuf[9], rbuf[10], rbuf[11], rbuf[4]);\r
+ }\r
+ \r
+ /* Report acceleration sensor information */\r
+ if (atomic_read(&sensor->flags.a_flag) && (rbuf[0] & ACC_DATA_READY)) {\r
+ input_report_abs(sensor->input_dev, ABS_X, rbuf[1]);\r
+ input_report_abs(sensor->input_dev, ABS_Y, rbuf[2]);\r
+ input_report_abs(sensor->input_dev, ABS_Z, rbuf[3]);\r
+ input_report_abs(sensor->input_dev, ABS_WHEEL, rbuf[4]);\r
+ \r
+ DBG("%s:a_flag:x=%d,y=%d,z=%d,WHEEL=%d\n",__func__,rbuf[1], rbuf[2], rbuf[3], rbuf[4]);\r
+ }\r
+ \r
+ /* Report magnetic vector information */\r
+ if (atomic_read(&sensor->flags.mv_flag) && (rbuf[0] & MAG_DATA_READY)) {\r
+ input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[5]);\r
+ input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[6]);\r
+ input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[7]); \r
+ input_report_abs(sensor->input_dev, ABS_HAT1X, rbuf[8]);\r
+ \r
+ DBG("%s:mv_flag:x=%d,y=%d,z=%d,status=%d\n",__func__,rbuf[5], rbuf[6], rbuf[7], rbuf[8]);\r
+ }\r
+ \r
+ input_sync(sensor->input_dev);\r
+\r
+ memcpy(g_akm_rbuf, rbuf, 12); //used for ECS_IOCTL_GET_ACCEL\r
+}\r
+\r
+\r
+\r
+static int compass_dev_open(struct inode *inode, struct file *file)\r
+{\r
+#ifdef SENSOR_DEBUG_TYPE\r
+ struct sensor_private_data* sensor = \r
+ (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+#endif\r
+ int result = 0;\r
+ DBG("%s\n",__func__);\r
+\r
+ return result;\r
+}\r
+\r
+\r
+static int compass_dev_release(struct inode *inode, struct file *file)\r
+{\r
+#ifdef SENSOR_DEBUG_TYPE\r
+ struct sensor_private_data* sensor = \r
+ (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+#endif\r
+ int result = 0; \r
+ DBG("%s\n",__func__);\r
+\r
+ return result;\r
+}\r
+\r
+static int compass_akm_set_mode(struct i2c_client *client, char mode)\r
+{\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ int result = 0; \r
+\r
+ switch(mode & 0x0f)\r
+ {\r
+ case AK8963_MODE_SNG_MEASURE:\r
+ case AK8963_MODE_SELF_TEST: \r
+ case AK8963_MODE_FUSE_ACCESS: \r
+ if(sensor->status_cur == SENSOR_OFF)\r
+ {\r
+ if(sensor->pdata->irq_enable)\r
+ {\r
+ //DBG("%s:enable irq=%d\n",__func__,client->irq);\r
+ //enable_irq(client->irq);\r
+ } \r
+ else\r
+ {\r
+ schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms));\r
+ }\r
+ \r
+ sensor->status_cur = SENSOR_ON;\r
+ }\r
+\r
+ break;\r
+\r
+ case AK8963_MODE_POWERDOWN: \r
+ if(sensor->status_cur == SENSOR_ON)\r
+ {\r
+ if(sensor->pdata->irq_enable)\r
+ { \r
+ //DBG("%s:disable irq=%d\n",__func__,client->irq);\r
+ //disable_irq_nosync(client->irq);//disable irq\r
+ }\r
+ else\r
+ cancel_delayed_work_sync(&sensor->delaywork); \r
+\r
+ sensor->status_cur = SENSOR_OFF;\r
+ }\r
+ break;\r
+\r
+ }\r
+ \r
+ switch(mode & 0x0f)\r
+ {\r
+ case AK8963_MODE_SNG_MEASURE: \r
+ result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode);\r
+ if(result)\r
+ printk("%s:i2c error,mode=%d\n",__func__,mode); \r
+ break;\r
+ case AK8963_MODE_SELF_TEST: \r
+ result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode);\r
+ if(result)\r
+ printk("%s:i2c error,mode=%d\n",__func__,mode);\r
+ break;\r
+ case AK8963_MODE_FUSE_ACCESS:\r
+ result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode);\r
+ if(result)\r
+ printk("%s:i2c error,mode=%d\n",__func__,mode);\r
+ break;\r
+ case AK8963_MODE_POWERDOWN:\r
+ /* Set powerdown mode */\r
+ result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8963_MODE_POWERDOWN);\r
+ if(result)\r
+ printk("%s:i2c error,mode=%d\n",__func__,mode);\r
+ udelay(100);\r
+ break;\r
+ default:\r
+ printk("%s: Unknown mode(%d)", __func__, mode);\r
+ result = -EINVAL;\r
+ break;\r
+ }\r
+ DBG("%s:mode=0x%x\n",__func__,mode);\r
+ return result;\r
+\r
+}\r
+\r
+static int compass_akm_reset(struct i2c_client *client)\r
+{\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ int result = 0; \r
+ \r
+ if(sensor->pdata->reset_pin > 0)\r
+ {\r
+ gpio_direction_output(sensor->pdata->reset_pin, GPIO_LOW);\r
+ udelay(10);\r
+ gpio_direction_output(sensor->pdata->reset_pin, GPIO_HIGH);\r
+ }\r
+ else \r
+ {\r
+ /* Set measure mode */\r
+ result = sensor_write_reg(client, AK8963_REG_CNTL2, AK8963_MODE_SNG_MEASURE);\r
+ if(result)\r
+ printk("%s:fail to Set measure mode\n",__func__);\r
+ }\r
+ \r
+ udelay(100);\r
+ \r
+ return result;\r
+\r
+}\r
+\r
+\r
+\r
+static int compass_akm_get_openstatus(void)\r
+{ \r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) != 0));\r
+ return atomic_read(&sensor->flags.open_flag);\r
+}\r
+\r
+static int compass_akm_get_closestatus(void)\r
+{ \r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) <= 0));\r
+ return atomic_read(&sensor->flags.open_flag);\r
+}\r
+\r
+\r
+/* ioctl - I/O control */\r
+static long compass_dev_ioctl(struct file *file,\r
+ unsigned int cmd, unsigned long arg)\r
+{\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client);\r
+ struct i2c_client *client = this_client;\r
+ void __user *argp = (void __user *)arg;\r
+ int result = 0;\r
+ struct akm_platform_data compass;\r
+ \r
+ /* NOTE: In this function the size of "char" should be 1-byte. */\r
+ char compass_data[SENSOR_DATA_SIZE]; /* for GETDATA */\r
+ char rwbuf[RWBUF_SIZE]; /* for READ/WRITE */\r
+ char mode; /* for SET_MODE*/\r
+ int value[12]; /* for SET_YPR */\r
+ int status; /* for OPEN/CLOSE_STATUS */\r
+ int ret = -1; /* Return value. */\r
+ \r
+ //int8_t sensor_buf[SENSOR_DATA_SIZE]; /* for GETDATA */\r
+ //int32_t ypr_buf[YPR_DATA_SIZE]; /* for SET_YPR */\r
+ int16_t acc_buf[3]; /* for GET_ACCEL */\r
+ int64_t delay[AKM_NUM_SENSORS]; /* for GET_DELAY */\r
+\r
+ char layout; /* for GET_LAYOUT */\r
+ char outbit; /* for GET_OUTBIT */\r
+\r
+ switch (cmd) {\r
+ case ECS_IOCTL_WRITE:\r
+ case ECS_IOCTL_READ:\r
+ if (argp == NULL) {\r
+ return -EINVAL;\r
+ }\r
+ if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_SET_MODE:\r
+ if (argp == NULL) {\r
+ return -EINVAL;\r
+ }\r
+ if (copy_from_user(&mode, argp, sizeof(mode))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_SET_YPR:\r
+ if (argp == NULL) {\r
+ return -EINVAL;\r
+ }\r
+ if (copy_from_user(&value, argp, sizeof(value))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GETDATA:\r
+ case ECS_IOCTL_GET_OPEN_STATUS:\r
+ case ECS_IOCTL_GET_CLOSE_STATUS:\r
+ case ECS_IOCTL_GET_DELAY:\r
+ case ECS_IOCTL_GET_LAYOUT:\r
+ case ECS_IOCTL_GET_OUTBIT:\r
+ case ECS_IOCTL_GET_ACCEL:\r
+ /* Just check buffer pointer */\r
+ if (argp == NULL) {\r
+ printk("%s:invalid argument\n",__func__);\r
+ return -EINVAL;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ switch (cmd) {\r
+ case ECS_IOCTL_WRITE:\r
+ DBG("%s:ECS_IOCTL_WRITE start\n",__func__);\r
+ mutex_lock(&sensor->operation_mutex);\r
+ if ((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) { \r
+ mutex_unlock(&sensor->operation_mutex);\r
+ return -EINVAL;\r
+ }\r
+ ret = sensor_tx_data(client, &rwbuf[1], rwbuf[0]);\r
+ if (ret < 0) { \r
+ mutex_unlock(&sensor->operation_mutex); \r
+ printk("%s:fait to tx data\n",__func__);\r
+ return ret;\r
+ } \r
+ mutex_unlock(&sensor->operation_mutex);\r
+ break;\r
+ case ECS_IOCTL_READ: \r
+ DBG("%s:ECS_IOCTL_READ start\n",__func__);\r
+ mutex_lock(&sensor->operation_mutex);\r
+ if ((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) { \r
+ mutex_unlock(&sensor->operation_mutex); \r
+ printk("%s:data is error\n",__func__);\r
+ return -EINVAL;\r
+ }\r
+ ret = sensor_rx_data(client, &rwbuf[1], rwbuf[0]);\r
+ if (ret < 0) { \r
+ mutex_unlock(&sensor->operation_mutex); \r
+ printk("%s:fait to rx data\n",__func__);\r
+ return ret;\r
+ } \r
+ mutex_unlock(&sensor->operation_mutex);\r
+ break;\r
+ case ECS_IOCTL_SET_MODE:\r
+ DBG("%s:ECS_IOCTL_SET_MODE start\n",__func__); \r
+ mutex_lock(&sensor->operation_mutex);\r
+ if(sensor->ops->ctrl_data != mode)\r
+ {\r
+ ret = compass_akm_set_mode(client, mode);\r
+ if (ret < 0) {\r
+ printk("%s:fait to set mode\n",__func__); \r
+ mutex_unlock(&sensor->operation_mutex);\r
+ return ret;\r
+ }\r
+ \r
+ sensor->ops->ctrl_data = mode;\r
+ }\r
+ mutex_unlock(&sensor->operation_mutex);\r
+ break;\r
+ case ECS_IOCTL_GETDATA:\r
+ DBG("%s:ECS_IOCTL_GETDATA start\n",__func__);\r
+ mutex_lock(&sensor->data_mutex); \r
+ memcpy(compass_data, sensor->sensor_data, SENSOR_DATA_SIZE); //get data from buffer\r
+ mutex_unlock(&sensor->data_mutex);\r
+ break;\r
+ case ECS_IOCTL_SET_YPR: \r
+ DBG("%s:ECS_IOCTL_SET_YPR start\n",__func__);\r
+ mutex_lock(&sensor->data_mutex);\r
+ compass_set_YPR(value); \r
+ mutex_unlock(&sensor->data_mutex);\r
+ break;\r
+ case ECS_IOCTL_GET_OPEN_STATUS:\r
+ status = compass_akm_get_openstatus(); \r
+ DBG("%s:openstatus=%d\n",__func__,status);\r
+ break;\r
+ case ECS_IOCTL_GET_CLOSE_STATUS:\r
+ status = compass_akm_get_closestatus(); \r
+ DBG("%s:closestatus=%d\n",__func__,status);\r
+ break;\r
+ case ECS_IOCTL_GET_DELAY:\r
+ DBG("%s:ECS_IOCTL_GET_DELAY start\n",__func__);\r
+ mutex_lock(&sensor->operation_mutex);\r
+ delay[0] = sensor->flags.delay;\r
+ delay[1] = sensor->flags.delay;\r
+ delay[2] = sensor->flags.delay;\r
+ mutex_unlock(&sensor->operation_mutex);\r
+ break;\r
+ \r
+ case ECS_IOCTL_GET_PLATFORM_DATA: \r
+ DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__);\r
+ memcpy(compass.m_layout, sensor->pdata->m_layout, sizeof(sensor->pdata->m_layout));\r
+ memcpy(compass.project_name, sensor->pdata->project_name, sizeof(sensor->pdata->project_name));\r
+ ret = copy_to_user(argp, &compass, sizeof(compass));\r
+ if(ret < 0)\r
+ {\r
+ printk("%s:error,ret=%d\n",__FUNCTION__, ret);\r
+ return ret;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_LAYOUT:\r
+ DBG("%s:ECS_IOCTL_GET_LAYOUT start\n",__func__);\r
+ layout = 1; //sensor->pdata->layout;\r
+ break;\r
+ case ECS_IOCTL_GET_OUTBIT:\r
+ DBG("%s:ECS_IOCTL_GET_OUTBIT start\n",__func__);\r
+ outbit = 1; //sensor->pdata->outbit;\r
+ break;\r
+ case ECS_IOCTL_RESET:\r
+ DBG("%s:ECS_IOCTL_RESET start\n",__func__);\r
+ ret = compass_akm_reset(client);\r
+ if (ret < 0)\r
+ return ret;\r
+ break;\r
+ case ECS_IOCTL_GET_ACCEL:\r
+ DBG("%s:ECS_IOCTL_GET_ACCEL start,no accel data\n",__func__);\r
+ mutex_lock(&sensor->operation_mutex);\r
+ acc_buf[0] = g_akm_rbuf[6];\r
+ acc_buf[1] = g_akm_rbuf[7];\r
+ acc_buf[2] = g_akm_rbuf[8];\r
+ mutex_unlock(&sensor->operation_mutex);\r
+ break;\r
+\r
+ default:\r
+ return -ENOTTY;\r
+ }\r
+\r
+ switch (cmd) {\r
+ case ECS_IOCTL_READ:\r
+ if (copy_to_user(argp, &rwbuf, rwbuf[0]+1)) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GETDATA:\r
+ if (copy_to_user(argp, &compass_data, sizeof(compass_data))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_OPEN_STATUS:\r
+ case ECS_IOCTL_GET_CLOSE_STATUS:\r
+ if (copy_to_user(argp, &status, sizeof(status))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_DELAY:\r
+ if (copy_to_user(argp, &delay, sizeof(delay))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_LAYOUT:\r
+ if (copy_to_user(argp, &layout, sizeof(layout))) {\r
+ printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_OUTBIT:\r
+ if (copy_to_user(argp, &outbit, sizeof(outbit))) {\r
+ printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_GET_ACCEL:\r
+ if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) {\r
+ printk("%s:error:%d\n",__FUNCTION__,__LINE__);\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return result;\r
+}\r
+\r
+static struct file_operations compass_dev_fops =\r
+{\r
+ .owner = THIS_MODULE,\r
+ .open = compass_dev_open,\r
+ .release = compass_dev_release, \r
+ .unlocked_ioctl = compass_dev_ioctl,\r
+};\r
+\r
+\r
+static struct miscdevice compass_dev_device =\r
+{ \r
+ .minor = MISC_DYNAMIC_MINOR,\r
+ .name = "akm8963_dev",\r
+ .fops = &compass_dev_fops,\r
+};\r
+\r
+struct sensor_operate compass_akm8963_ops = {\r
+ .name = "akm8963",\r
+ .type = SENSOR_TYPE_COMPASS, //it is important\r
+ .id_i2c = COMPASS_ID_AK8963,\r
+ .read_reg = AK8963_REG_ST1, //read data\r
+ .read_len = SENSOR_DATA_SIZE, //data length\r
+ .id_reg = AK8963_REG_WIA, //read id\r
+ .id_data = AK8963_DEVICE_ID,\r
+ .precision = 8, //12 bits\r
+ .ctrl_reg = AK8963_REG_CNTL1, //enable or disable \r
+ .int_status_reg = SENSOR_UNKNOW_DATA, //not exist\r
+ .range = {-0xffff,0xffff},\r
+ .trig = IRQF_TRIGGER_RISING, //if LEVEL interrupt then IRQF_ONESHOT\r
+ .active = sensor_active, \r
+ .init = sensor_init,\r
+ .report = sensor_report_value, \r
+ .misc_dev = NULL, //private misc support\r
+};\r
+\r
+/****************operate according to sensor chip:end************/\r
+\r
+//function name should not be changed\r
+static struct sensor_operate *compass_get_ops(void)\r
+{\r
+ return &compass_akm8963_ops; \r
+}\r
+\r
+\r
+static int __init compass_akm8963_init(void)\r
+{\r
+ struct sensor_operate *ops = compass_get_ops();\r
+ int result = 0;\r
+ int type = ops->type;\r
+ result = sensor_register_slave(type, NULL, NULL, compass_get_ops);\r
+\r
+ result = misc_register(&compass_dev_device);\r
+ if (result < 0) {\r
+ printk("%s:fail to register misc device %s\n", __func__, compass_dev_device.name);\r
+ goto error;\r
+ }\r
+error: \r
+ return result;\r
+}\r
+\r
+static void __exit compass_akm8963_exit(void)\r
+{\r
+ struct sensor_operate *ops = compass_get_ops();\r
+ int type = ops->type;\r
+ sensor_unregister_slave(type, NULL, NULL, compass_get_ops);\r
+}\r
+\r
+\r
+module_init(compass_akm8963_init);\r
+module_exit(compass_akm8963_exit);\r
+\r
+\r
#ifdef CONFIG_HAS_EARLYSUSPEND\r
#include <linux/earlysuspend.h>\r
#endif\r
-#include <linux/akm8975.h>\r
+\r
#include <linux/sensor-dev.h>\r
\r
#define SENSOR_DATA_SIZE 8\r
#define DBG(x...)\r
#endif\r
\r
+/*! \name AK8975 operation mode\r
+ \anchor AK8975_Mode\r
+ Defines an operation mode of the AK8975.*/\r
+/*! @{*/\r
+#define AK8975_MODE_SNG_MEASURE 0x01\r
+#define AK8975_MODE_SELF_TEST 0x08\r
+#define AK8975_MODE_FUSE_ACCESS 0x0F\r
+#define AK8975_MODE_POWERDOWN 0x00\r
+/*! @}*/\r
+\r
+#define SENSOR_DATA_SIZE 8 /* Rx buffer size, i.e from ST1 to ST2 */\r
+#define RWBUF_SIZE 16 /* Read/Write buffer size.*/\r
+\r
+\r
+/*! \name AK8975 register address\r
+\anchor AK8975_REG\r
+Defines a register address of the AK8975.*/\r
+/*! @{*/\r
+#define AK8975_REG_WIA 0x00\r
+#define AK8975_REG_INFO 0x01\r
+#define AK8975_REG_ST1 0x02\r
+#define AK8975_REG_HXL 0x03\r
+#define AK8975_REG_HXH 0x04\r
+#define AK8975_REG_HYL 0x05\r
+#define AK8975_REG_HYH 0x06\r
+#define AK8975_REG_HZL 0x07\r
+#define AK8975_REG_HZH 0x08\r
+#define AK8975_REG_ST2 0x09\r
+#define AK8975_REG_CNTL 0x0A\r
+#define AK8975_REG_RSV 0x0B\r
+#define AK8975_REG_ASTC 0x0C\r
+#define AK8975_REG_TS1 0x0D\r
+#define AK8975_REG_TS2 0x0E\r
+#define AK8975_REG_I2CDIS 0x0F\r
+/*! @}*/\r
+\r
+/*! \name AK8975 fuse-rom address\r
+\anchor AK8975_FUSE\r
+Defines a read-only address of the fuse ROM of the AK8975.*/\r
+/*! @{*/\r
+#define AK8975_FUSE_ASAX 0x10\r
+#define AK8975_FUSE_ASAY 0x11\r
+#define AK8975_FUSE_ASAZ 0x12\r
+/*! @}*/\r
+\r
+#define AK8975_INFO_DATA (0x01<<3)\r
+\r
+\r
+#define COMPASS_IOCTL_MAGIC 'c'\r
+\r
+/* IOCTLs for AKM library */\r
+#define ECS_IOCTL_WRITE _IOW(COMPASS_IOCTL_MAGIC, 0x01, char*)\r
+#define ECS_IOCTL_READ _IOWR(COMPASS_IOCTL_MAGIC, 0x02, char*)\r
+#define ECS_IOCTL_RESET _IO(COMPASS_IOCTL_MAGIC, 0x03) /* NOT used in AK8975 */\r
+#define ECS_IOCTL_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x04, short)\r
+#define ECS_IOCTL_GETDATA _IOR(COMPASS_IOCTL_MAGIC, 0x05, char[SENSOR_DATA_SIZE])\r
+#define ECS_IOCTL_SET_YPR _IOW(COMPASS_IOCTL_MAGIC, 0x06, short[12])\r
+#define ECS_IOCTL_GET_OPEN_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x07, int)\r
+#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x08, int)\r
+#define ECS_IOCTL_GET_LAYOUT _IOR(COMPASS_IOCTL_MAGIC, 0x09, char)\r
+#define ECS_IOCTL_GET_ACCEL _IOR(COMPASS_IOCTL_MAGIC, 0x0A, short[3])\r
+#define ECS_IOCTL_GET_OUTBIT _IOR(COMPASS_IOCTL_MAGIC, 0x0B, char)\r
+#define ECS_IOCTL_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x30, short)\r
+#define ECS_IOCTL_GET_PROJECT_NAME _IOR(COMPASS_IOCTL_MAGIC, 0x0D, char[64])\r
+#define ECS_IOCTL_GET_MATRIX _IOR(COMPASS_IOCTL_MAGIC, 0x0E, short [4][3][3])\r
+#define ECS_IOCTL_GET_PLATFORM_DATA _IOR(COMPASS_IOCTL_MAGIC, 0x0E, struct akm_platform_data)\r
\r
\r
#define AK8975_DEVICE_ID 0x48\r
static struct i2c_client *this_client;\r
\r
-static atomic_t m_flag;\r
-static atomic_t a_flag;\r
-static atomic_t mv_flag;\r
-static atomic_t open_flag;\r
-static short akmd_delay = 100;\r
-static DECLARE_WAIT_QUEUE_HEAD(open_wq);\r
+\r
\r
\r
/****************operate according to sensor chip:start************/\r
struct sensor_private_data *sensor =\r
(struct sensor_private_data *) i2c_get_clientdata(client); \r
int result = 0;\r
+ int info = 0;\r
\r
this_client = client; \r
\r
}\r
\r
sensor->status_cur = SENSOR_OFF;\r
-#if 0 \r
- sensor->ops->ctrl_data = 0;\r
- result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);\r
- if(result)\r
+ \r
+ info = sensor_read_reg(client, AK8975_REG_INFO);\r
+ if((info & (0x0f<<3)) != AK8975_INFO_DATA)\r
+ \r
{\r
- printk("%s:line=%d,error\n",__func__,__LINE__);\r
- return result;\r
+ printk("%s:info=0x%x,it is not %s\n",__func__, info, sensor->ops->name);\r
+ result = -1;\r
}\r
-#endif\r
+ \r
DBG("%s:status_cur=%d\n",__func__, sensor->status_cur);\r
return result;\r
}\r
#ifdef SENSOR_DEBUG_TYPE \r
DBG("%s:",__func__);\r
for(i=0; i<sensor->ops->read_len; i++)\r
- DBG("%d,",buffer[i]);\r
+ DBG("0x%x,",buffer[i]);\r
DBG("\n");\r
#endif \r
\r
(struct sensor_private_data *) i2c_get_clientdata(this_client); \r
\r
/* Report magnetic sensor information */\r
- if (atomic_read(&m_flag)) {\r
+ if (atomic_read(&sensor->flags.m_flag)) {\r
input_report_abs(sensor->input_dev, ABS_RX, rbuf[0]);\r
input_report_abs(sensor->input_dev, ABS_RY, rbuf[1]);\r
input_report_abs(sensor->input_dev, ABS_RZ, rbuf[2]);\r
}\r
\r
/* Report acceleration sensor information */\r
- if (atomic_read(&a_flag)) {\r
+ if (atomic_read(&sensor->flags.a_flag)) {\r
input_report_abs(sensor->input_dev, ABS_X, rbuf[6]);\r
input_report_abs(sensor->input_dev, ABS_Y, rbuf[7]);\r
input_report_abs(sensor->input_dev, ABS_Z, rbuf[8]);\r
}\r
\r
/* Report magnetic vector information */\r
- if (atomic_read(&mv_flag)) {\r
+ if (atomic_read(&sensor->flags.mv_flag)) {\r
input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[9]);\r
input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[10]);\r
input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[11]);\r
}\r
\r
\r
-\r
-static int compass_aot_open(struct inode *inode, struct file *file)\r
-{\r
-#ifdef SENSOR_DEBUG_TYPE\r
- struct sensor_private_data* sensor =\r
- (struct sensor_private_data *)i2c_get_clientdata(this_client);\r
-#endif\r
- int result = 0;\r
- int flag = 0;\r
- flag = atomic_read(&open_flag);\r
- if(!flag)\r
- { \r
- atomic_set(&open_flag, 1);\r
- wake_up(&open_wq);\r
- }\r
-\r
- DBG("%s\n", __func__);\r
- return result;\r
-}\r
-\r
-\r
-static int compass_aot_release(struct inode *inode, struct file *file)\r
-{ \r
-#ifdef SENSOR_DEBUG_TYPE\r
- struct sensor_private_data* sensor =\r
- (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
-#endif\r
- //struct i2c_client *client = this_client;\r
- int result = 0;\r
- int flag = 0;\r
- flag = atomic_read(&open_flag);\r
- if(flag)\r
- {\r
- atomic_set(&open_flag, 0);\r
- wake_up(&open_wq); \r
- }\r
- \r
- DBG("%s\n", __func__);\r
- return result;\r
-}\r
-\r
-\r
-/* ioctl - I/O control */\r
-static long compass_aot_ioctl(struct file *file,\r
- unsigned int cmd, unsigned long arg)\r
-{\r
-#ifdef SENSOR_DEBUG_TYPE\r
- struct sensor_private_data* sensor = \r
- (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
-#endif\r
- void __user *argp = (void __user *)arg;\r
- int result = 0;\r
- short flag;\r
- \r
- switch (cmd) {\r
- case ECS_IOCTL_APP_SET_MFLAG:\r
- case ECS_IOCTL_APP_SET_AFLAG:\r
- case ECS_IOCTL_APP_SET_MVFLAG:\r
- if (copy_from_user(&flag, argp, sizeof(flag))) {\r
- return -EFAULT;\r
- }\r
- if (flag < 0 || flag > 1) {\r
- return -EINVAL;\r
- }\r
- break;\r
- case ECS_IOCTL_APP_SET_DELAY:\r
- if (copy_from_user(&flag, argp, sizeof(flag))) {\r
- return -EFAULT;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- \r
- switch (cmd) {\r
- case ECS_IOCTL_APP_SET_MFLAG: \r
- atomic_set(&m_flag, flag); \r
- DBG("%s:ECS_IOCTL_APP_SET_MFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_GET_MFLAG: \r
- flag = atomic_read(&m_flag);\r
- DBG("%s:ECS_IOCTL_APP_GET_MFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_SET_AFLAG: \r
- atomic_set(&a_flag, flag); \r
- DBG("%s:ECS_IOCTL_APP_SET_AFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_GET_AFLAG:\r
- flag = atomic_read(&a_flag); \r
- DBG("%s:ECS_IOCTL_APP_GET_AFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_SET_MVFLAG: \r
- atomic_set(&mv_flag, flag); \r
- DBG("%s:ECS_IOCTL_APP_SET_MVFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_GET_MVFLAG: \r
- flag = atomic_read(&mv_flag); \r
- DBG("%s:ECS_IOCTL_APP_GET_MVFLAG,flag=%d\n", __func__,flag);\r
- break;\r
- case ECS_IOCTL_APP_SET_DELAY:\r
- akmd_delay = flag;\r
- break;\r
- case ECS_IOCTL_APP_GET_DELAY:\r
- flag = akmd_delay;\r
- break;\r
- default:\r
- return -ENOTTY;\r
- }\r
- \r
- switch (cmd) {\r
- case ECS_IOCTL_APP_GET_MFLAG:\r
- case ECS_IOCTL_APP_GET_AFLAG:\r
- case ECS_IOCTL_APP_GET_MVFLAG:\r
- case ECS_IOCTL_APP_GET_DELAY:\r
- if (copy_to_user(argp, &flag, sizeof(flag))) {\r
- return -EFAULT;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
-\r
- return result;\r
-}\r
-\r
static int compass_dev_open(struct inode *inode, struct file *file)\r
{\r
#ifdef SENSOR_DEBUG_TYPE\r
\r
static int compass_akm_get_openstatus(void)\r
{\r
- wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0));\r
- return atomic_read(&open_flag);\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) != 0));\r
+ return atomic_read(&sensor->flags.open_flag);\r
}\r
\r
static int compass_akm_get_closestatus(void)\r
{\r
- wait_event_interruptible(open_wq, (atomic_read(&open_flag) <= 0));\r
- return atomic_read(&open_flag);\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); \r
+ wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) <= 0));\r
+ return atomic_read(&sensor->flags.open_flag);\r
}\r
\r
\r
static long compass_dev_ioctl(struct file *file,\r
unsigned int cmd, unsigned long arg)\r
{\r
- struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client);\r
+ struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client);\r
struct i2c_client *client = this_client;\r
void __user *argp = (void __user *)arg;\r
int result = 0;\r
- struct akm8975_platform_data compass;\r
+ struct akm_platform_data compass;\r
\r
/* NOTE: In this function the size of "char" should be 1-byte. */\r
char compass_data[SENSOR_DATA_SIZE];/* for GETDATA */\r
DBG("%s:closestatus=%d\n",__func__,status);\r
break;\r
case ECS_IOCTL_GET_DELAY:\r
- delay = akmd_delay;\r
+ delay = sensor->flags.delay;\r
break;\r
case ECS_IOCTL_GET_PLATFORM_DATA: \r
DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__);\r
return result;\r
}\r
\r
-\r
-static struct file_operations compass_aot_fops =\r
-{\r
- .owner = THIS_MODULE,\r
- .unlocked_ioctl = compass_aot_ioctl,\r
- .open = compass_aot_open,\r
- .release = compass_aot_release,\r
-};\r
-\r
-\r
-\r
-static struct miscdevice compass_aot_device =\r
-{ \r
- .minor = MISC_DYNAMIC_MINOR,\r
- .name = "akm8975_aot",\r
- .fops = &compass_aot_fops,\r
-};\r
-\r
-\r
static struct file_operations compass_dev_fops =\r
{\r
.owner = THIS_MODULE,\r
.fops = &compass_dev_fops,\r
};\r
\r
-struct sensor_operate akm8975_akm8975_ops = {\r
+struct sensor_operate compass_akm8975_ops = {\r
.name = "akm8975",\r
.type = SENSOR_TYPE_COMPASS, //it is important\r
.id_i2c = COMPASS_ID_AK8975,\r
.id_data = AK8975_DEVICE_ID,\r
.precision = 8, //12 bits\r
.ctrl_reg = AK8975_REG_CNTL, //enable or disable \r
- .int_status_reg = SENSOR_UNKNOW_DATA, //not exist\r
+ .int_status_reg = SENSOR_UNKNOW_DATA, //not exist\r
.range = {-0xffff,0xffff},\r
.trig = IRQF_TRIGGER_RISING, //if LEVEL interrupt then IRQF_ONESHOT\r
.active = sensor_active, \r
.init = sensor_init,\r
.report = sensor_report_value, \r
- .misc_dev = &compass_dev_device, //private misc support\r
+ .misc_dev = NULL, //private misc support\r
};\r
\r
/****************operate according to sensor chip:end************/\r
//function name should not be changed\r
static struct sensor_operate *compass_get_ops(void)\r
{\r
- return &akm8975_akm8975_ops;\r
+ return &compass_akm8975_ops; \r
}\r
\r
\r
int type = ops->type;\r
result = sensor_register_slave(type, NULL, NULL, compass_get_ops);\r
\r
- result = misc_register(&compass_aot_device);\r
+ result = misc_register(&compass_dev_device);\r
if (result < 0) {\r
- printk("%s:fail to register misc device %s\n", __func__, compass_aot_device.name);\r
+ printk("%s:fail to register misc device %s\n", __func__, compass_dev_device.name);\r
goto error;\r
}\r
-\r
- /* As default, report all information */\r
- atomic_set(&m_flag, 1);\r
- atomic_set(&a_flag, 1);\r
- atomic_set(&mv_flag, 1); \r
- atomic_set(&open_flag, 0); \r
- init_waitqueue_head(&open_wq);\r
- \r
- DBG("%s\n",__func__);\r
-error:\r
+error: \r
return result;\r
}\r
\r
#ifdef CONFIG_HAS_EARLYSUSPEND\r
#include <linux/earlysuspend.h>\r
#endif\r
-#include <linux/akm8975.h>\r
#include <linux/l3g4200d.h>\r
#include <linux/sensor-dev.h>\r
\r
#define DBG(x...)\r
#endif\r
\r
-#define SENSOR_VERSION_AND_TIME "sensor-dev.c v1.1 add pressure and temperature support 2013-2-27"\r
+#if 0\r
+sensor-dev.c v1.1 add pressure and temperature support 2013-2-27\r
+sensor-dev.c v1.2 add akm8963 support 2013-3-10\r
+#endif\r
+#define SENSOR_VERSION_AND_TIME "sensor-dev.c v1.2 add akm8963 support 2013-3-10"\r
\r
\r
struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES];\r
\r
static int compass_dev_open(struct inode *inode, struct file *file)\r
{\r
- //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
- //struct i2c_client *client = sensor->client;\r
+ struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
+ //struct i2c_client *client = sensor->client; \r
+\r
int result = 0;\r
- \r
- //to do\r
+ int flag = 0;\r
+ flag = atomic_read(&sensor->flags.open_flag);\r
+ if(!flag)\r
+ { \r
+ atomic_set(&sensor->flags.open_flag, 1);\r
+ wake_up(&sensor->flags.open_wq);\r
+ }\r
+\r
+ DBG("%s\n", __func__);\r
return result;\r
}\r
\r
\r
+\r
static int compass_dev_release(struct inode *inode, struct file *file)\r
{\r
- //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
- //struct i2c_client *client = sensor->client; \r
+ struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
+ //struct i2c_client *client = sensor->client;\r
+ //void __user *argp = (void __user *)arg;\r
int result = 0;\r
-\r
- //to do\r
+ int flag = 0;\r
+ flag = atomic_read(&sensor->flags.open_flag);\r
+ if(flag)\r
+ {\r
+ atomic_set(&sensor->flags.open_flag, 0);\r
+ wake_up(&sensor->flags.open_wq); \r
+ }\r
+ \r
+ DBG("%s\n", __func__);\r
return result;\r
}\r
\r
\r
+\r
/* ioctl - I/O control */\r
static long compass_dev_ioctl(struct file *file,\r
unsigned int cmd, unsigned long arg)\r
{\r
- //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
- //struct i2c_client *client = sensor->client;\r
- //void __user *argp = (void __user *)arg;\r
+ struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS];\r
+ struct i2c_client *client = sensor->client;\r
+ void __user *argp = (void __user *)arg;\r
int result = 0;\r
+ short flag;\r
+ \r
+ switch (cmd) {\r
+ case ECS_IOCTL_APP_SET_MFLAG:\r
+ case ECS_IOCTL_APP_SET_AFLAG:\r
+ case ECS_IOCTL_APP_SET_MVFLAG:\r
+ if (copy_from_user(&flag, argp, sizeof(flag))) {\r
+ return -EFAULT;\r
+ }\r
+ if (flag < 0 || flag > 1) {\r
+ return -EINVAL;\r
+ }\r
+ break;\r
+ case ECS_IOCTL_APP_SET_DELAY:\r
+ if (copy_from_user(&flag, argp, sizeof(flag))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
\r
- //to do\r
+ switch (cmd) {\r
+ case ECS_IOCTL_APP_SET_MFLAG: \r
+ atomic_set(&sensor->flags.m_flag, flag); \r
+ DBG("%s:ECS_IOCTL_APP_SET_MFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_GET_MFLAG: \r
+ flag = atomic_read(&sensor->flags.m_flag);\r
+ DBG("%s:ECS_IOCTL_APP_GET_MFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_SET_AFLAG: \r
+ atomic_set(&sensor->flags.a_flag, flag); \r
+ DBG("%s:ECS_IOCTL_APP_SET_AFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_GET_AFLAG:\r
+ flag = atomic_read(&sensor->flags.a_flag); \r
+ DBG("%s:ECS_IOCTL_APP_GET_AFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_SET_MVFLAG: \r
+ atomic_set(&sensor->flags.mv_flag, flag); \r
+ DBG("%s:ECS_IOCTL_APP_SET_MVFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_GET_MVFLAG: \r
+ flag = atomic_read(&sensor->flags.mv_flag); \r
+ DBG("%s:ECS_IOCTL_APP_GET_MVFLAG,flag=%d\n", __func__,flag);\r
+ break;\r
+ case ECS_IOCTL_APP_SET_DELAY:\r
+ sensor->flags.delay = flag;\r
+ break;\r
+ case ECS_IOCTL_APP_GET_DELAY:\r
+ flag = sensor->flags.delay;\r
+ break;\r
+ default:\r
+ return -ENOTTY;\r
+ }\r
+ \r
+ switch (cmd) {\r
+ case ECS_IOCTL_APP_GET_MFLAG:\r
+ case ECS_IOCTL_APP_GET_AFLAG:\r
+ case ECS_IOCTL_APP_GET_MVFLAG:\r
+ case ECS_IOCTL_APP_GET_DELAY:\r
+ if (copy_to_user(argp, &flag, sizeof(flag))) {\r
+ return -EFAULT;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
return result;\r
}\r
\r
goto out_free_memory;\r
}\r
\r
+ if(pdata->reset_pin)\r
+ gpio_request(pdata->reset_pin,"sensor_reset_pin");\r
+\r
+ if(pdata->power_pin)\r
+ gpio_request(pdata->power_pin,"sensor_power_pin");\r
+ \r
memset(&(sensor->axis), 0, sizeof(struct sensor_axis) );\r
atomic_set(&(sensor->data_ready), 0);\r
init_waitqueue_head(&(sensor->data_ready_wq));\r
mutex_init(&sensor->sensor_mutex);\r
mutex_init(&sensor->i2c_mutex);\r
\r
+ /* As default, report all information */\r
+ atomic_set(&sensor->flags.m_flag, 1);\r
+ atomic_set(&sensor->flags.a_flag, 1);\r
+ atomic_set(&sensor->flags.mv_flag, 1); \r
+ atomic_set(&sensor->flags.open_flag, 0); \r
+ init_waitqueue_head(&sensor->flags.open_wq);\r
+ sensor->flags.delay = 100;\r
+\r
sensor->status_cur = SENSOR_OFF;\r
sensor->axis.x = 0;\r
sensor->axis.y = 0;\r
out_free_memory:\r
kfree(sensor);\r
out_no_free:\r
- dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);\r
+ dev_err(&client->adapter->dev, "%s failed %d\n\n", __func__, result);\r
return result;\r
\r
}\r
{"gs_mxc6225", ACCEL_ID_MXC6225},\r
/*compass*/\r
{"compass", COMPASS_ID_ALL},\r
- {"ak8975", COMPASS_ID_AK8975},\r
+ {"ak8975", COMPASS_ID_AK8975}, \r
+ {"ak8963", COMPASS_ID_AK8963},\r
{"mmc314x", COMPASS_ID_MMC314X},\r
/*gyroscope*/\r
{"gyro", GYRO_ID_ALL}, \r