From: luowei Date: Sat, 9 Mar 2013 07:57:37 +0000 (+0800) Subject: sensors:add akm8963 support,need update HAL X-Git-Tag: firefly_0821_release~7443 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3aae7adc71e33bea2b24f962a606db1a39aa45b5;p=firefly-linux-kernel-4.4.55.git sensors:add akm8963 support,need update HAL --- diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index 781964b007e4..bcdf8f2d4869 100755 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -187,6 +187,16 @@ struct akm8975_platform_data { int gpio_DRDY; }; +struct akm_platform_data { + short m_layout[4][3][3]; + char project_name[64]; + char layout; + char outbit; + int gpio_DRDY; + int gpio_RST; +}; + + struct sensor_platform_data { int type; int irq; diff --git a/drivers/input/sensors/compass/Kconfig b/drivers/input/sensors/compass/Kconfig index 72ab06c0c34f..bbd576c2df46 100755 --- a/drivers/input/sensors/compass/Kconfig +++ b/drivers/input/sensors/compass/Kconfig @@ -23,6 +23,16 @@ config COMPASS_AK8975 To compile this driver as a module, choose M here: the module will be called ak8975. +config COMPASS_AK8963 + tristate "Asahi Kasei AK8963 3-Axis Magnetometer" + depends on I2C + help + Say yes here to build support for Asahi Kasei AK8963 3-Axis Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak8963. + + config COMPASS_MMC328X tristate "Mmc328x 3-Axis Magnetometer" depends on I2C diff --git a/drivers/input/sensors/compass/Makefile b/drivers/input/sensors/compass/Makefile index dfd09bfa3ea5..73e1db629109 100755 --- a/drivers/input/sensors/compass/Makefile +++ b/drivers/input/sensors/compass/Makefile @@ -1,6 +1,6 @@ # # Makefile for industrial I/O Magnetometer sensors # -obj-$(CONFIG_COMPASS_AK8975) := ak8975.o -obj-$(CONFIG_COMPASS_AK8973) := ak8973.o -obj-$(CONFIG_COMPASS_MMC328X) := mmc328x.o \ No newline at end of file +obj-$(CONFIG_COMPASS_AK8975) += ak8975.o +obj-$(CONFIG_COMPASS_AK8963) += ak8963.o +obj-$(CONFIG_COMPASS_MMC328X) += mmc328x.o \ No newline at end of file diff --git a/drivers/input/sensors/compass/ak8963.c b/drivers/input/sensors/compass/ak8963.c new file mode 100755 index 000000000000..bf3af24812e6 --- /dev/null +++ b/drivers/input/sensors/compass/ak8963.c @@ -0,0 +1,789 @@ +/* drivers/input/sensors/access/akm8963.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#define SENSOR_DATA_SIZE 8 + +#if 0 +#define SENSOR_DEBUG_TYPE SENSOR_TYPE_COMPASS +#define DBG(x...) if(sensor->pdata->type == SENSOR_DEBUG_TYPE) printk(x) +#else +#define DBG(x...) +#endif + +#define SENSOR_DATA_SIZE 8 +#define YPR_DATA_SIZE 12 +#define RWBUF_SIZE 16 + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define AKM_NUM_SENSORS 3 + +#define ACC_DATA_READY (1<<(ACC_DATA_FLAG)) +#define MAG_DATA_READY (1<<(MAG_DATA_FLAG)) +#define ORI_DATA_READY (1<<(ORI_DATA_FLAG)) + +/*! \name AK8963 constant definition + \anchor AK8963_Def + Constant definitions of the AK8963.*/ +#define AK8963_MEASUREMENT_TIME_US 10000 + +/*! \name AK8963 operation mode + \anchor AK8963_Mode + Defines an operation mode of the AK8963.*/ +/*! @{*/ +#define AK8963_MODE_SNG_MEASURE 0x01 +#define AK8963_MODE_SELF_TEST 0x08 +#define AK8963_MODE_FUSE_ACCESS 0x0F +#define AK8963_MODE_POWERDOWN 0x00 + +/*! @}*/ + +/*! \name AK8963 register address +\anchor AK8963_REG +Defines a register address of the AK8963.*/ +/*! @{*/ +#define AK8963_REG_WIA 0x00 +#define AK8963_REG_INFO 0x01 +#define AK8963_REG_ST1 0x02 +#define AK8963_REG_HXL 0x03 +#define AK8963_REG_HXH 0x04 +#define AK8963_REG_HYL 0x05 +#define AK8963_REG_HYH 0x06 +#define AK8963_REG_HZL 0x07 +#define AK8963_REG_HZH 0x08 +#define AK8963_REG_ST2 0x09 +#define AK8963_REG_CNTL1 0x0A +#define AK8963_REG_CNTL2 0x0B +#define AK8963_REG_ASTC 0x0C +#define AK8963_REG_TS1 0x0D +#define AK8963_REG_TS2 0x0E +#define AK8963_REG_I2CDIS 0x0F +/*! @}*/ + +/*! \name AK8963 fuse-rom address +\anchor AK8963_FUSE +Defines a read-only address of the fuse ROM of the AK8963.*/ +/*! @{*/ +#define AK8963_FUSE_ASAX 0x10 +#define AK8963_FUSE_ASAY 0x11 +#define AK8963_FUSE_ASAZ 0x12 +/*! @}*/ + +#define AK8963_INFO_DATA (0x03<<3) + + +#define COMPASS_IOCTL_MAGIC 'c' + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_WRITE _IOW(COMPASS_IOCTL_MAGIC, 0x01, char*) +#define ECS_IOCTL_READ _IOWR(COMPASS_IOCTL_MAGIC, 0x02, char*) +#define ECS_IOCTL_RESET _IO(COMPASS_IOCTL_MAGIC, 0x03) /* NOT used in AK8975 */ +#define ECS_IOCTL_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x04, short) +#define ECS_IOCTL_GETDATA _IOR(COMPASS_IOCTL_MAGIC, 0x05, char[SENSOR_DATA_SIZE]) +#define ECS_IOCTL_SET_YPR _IOW(COMPASS_IOCTL_MAGIC, 0x06, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x07, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x08, int) +#define ECS_IOCTL_GET_LAYOUT _IOR(COMPASS_IOCTL_MAGIC, 0x09, char) +#define ECS_IOCTL_GET_ACCEL _IOR(COMPASS_IOCTL_MAGIC, 0x0A, short[3]) +#define ECS_IOCTL_GET_OUTBIT _IOR(COMPASS_IOCTL_MAGIC, 0x0B, char) +#define ECS_IOCTL_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x30, short) +#define ECS_IOCTL_GET_PROJECT_NAME _IOR(COMPASS_IOCTL_MAGIC, 0x0D, char[64]) +#define ECS_IOCTL_GET_MATRIX _IOR(COMPASS_IOCTL_MAGIC, 0x0E, short [4][3][3]) +#define ECS_IOCTL_GET_PLATFORM_DATA _IOR(COMPASS_IOCTL_MAGIC, 0x0E, struct akm_platform_data) + + + +#define AK8963_DEVICE_ID 0x48 +static struct i2c_client *this_client; + +static short g_akm_rbuf[12]; + + +/****************operate according to sensor chip:start************/ + +static int sensor_active(struct i2c_client *client, int enable, int rate) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + //sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + sensor->ops->ctrl_data = AK8963_MODE_SNG_MEASURE; + } + else + { + sensor->ops->ctrl_data = AK8963_MODE_POWERDOWN; + } + + DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + printk("%s:fail to active sensor\n",__func__); + + return result; + +} + +static int sensor_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char info = 0; + + this_client = client; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + info = sensor_read_reg(client, AK8963_REG_INFO); + if((info & (0x0f<<3)) != AK8963_INFO_DATA) + { + printk("%s:info=0x%x,it is not %s\n",__func__, info, sensor->ops->name); + result = -1; + } + + DBG("%s:status_cur=%d\n",__func__, sensor->status_cur); + return result; +} + +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + char buffer[8] = {0}; + unsigned char *stat; + unsigned char *stat2; + int ret = 0; + char value = 0; +#ifdef SENSOR_DEBUG_TYPE + int i; +#endif + if(sensor->ops->read_len < 8) //sensor->ops->read_len = 8 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 8); + + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + do { + *buffer = sensor->ops->read_reg; + ret = sensor_rx_data(client, buffer, sensor->ops->read_len); + if (ret < 0) + return ret; + } while (0); + + stat = &buffer[0]; + stat2 = &buffer[7]; + + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if ((*stat & 0x01) != 0x01) { + DBG(KERN_ERR "%s:ST is not set\n",__func__); + return -1; + } + + /* + * 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) + { + DBG(KERN_ERR "%s:compass data error\n",__func__); + return -2; + } + + /* + * 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) + { + DBG(KERN_ERR "%s:compass data overflow\n",__func__); + return -3; + } + + /* »¥³âµØ»º´æÊý¾Ý. */ + mutex_lock(&sensor->data_mutex); + memcpy(sensor->sensor_data, buffer, sensor->ops->read_len); + mutex_unlock(&sensor->data_mutex); +#ifdef SENSOR_DEBUG_TYPE + DBG("%s:",__func__); + for(i=0; iops->read_len; i++) + DBG("0x%x,",buffer[i]); + DBG("\n"); +#endif + + if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register + { + + value = sensor_read_reg(client, sensor->ops->int_status_reg); + DBG("%s:sensor int status :0x%x\n",__func__,value); + } + + + //trigger next measurement + ret = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(ret) + { + printk(KERN_ERR "%s:fail to set ctrl_data:0x%x\n",__func__,sensor->ops->ctrl_data); + return ret; + } + + return ret; +} + +static void compass_set_YPR(int *rbuf) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(this_client); + + /* No events are reported */ + if (!rbuf[0]) { + printk("%s:Don't waste a time.",__func__); + return; + } + + DBG("%s:buf[0]=0x%x\n",__func__, rbuf[0]); + + /* Report magnetic sensor information */ + if (atomic_read(&sensor->flags.m_flag) && (rbuf[0] & ORI_DATA_READY)) { + input_report_abs(sensor->input_dev, ABS_RX, rbuf[9]); + input_report_abs(sensor->input_dev, ABS_RY, rbuf[10]); + input_report_abs(sensor->input_dev, ABS_RZ, rbuf[11]); + input_report_abs(sensor->input_dev, ABS_RUDDER, rbuf[4]); + DBG("%s:m_flag:x=%d,y=%d,z=%d,RUDDER=%d\n",__func__,rbuf[9], rbuf[10], rbuf[11], rbuf[4]); + } + + /* Report acceleration sensor information */ + if (atomic_read(&sensor->flags.a_flag) && (rbuf[0] & ACC_DATA_READY)) { + input_report_abs(sensor->input_dev, ABS_X, rbuf[1]); + input_report_abs(sensor->input_dev, ABS_Y, rbuf[2]); + input_report_abs(sensor->input_dev, ABS_Z, rbuf[3]); + input_report_abs(sensor->input_dev, ABS_WHEEL, rbuf[4]); + + DBG("%s:a_flag:x=%d,y=%d,z=%d,WHEEL=%d\n",__func__,rbuf[1], rbuf[2], rbuf[3], rbuf[4]); + } + + /* Report magnetic vector information */ + if (atomic_read(&sensor->flags.mv_flag) && (rbuf[0] & MAG_DATA_READY)) { + input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[5]); + input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[6]); + input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[7]); + input_report_abs(sensor->input_dev, ABS_HAT1X, rbuf[8]); + + DBG("%s:mv_flag:x=%d,y=%d,z=%d,status=%d\n",__func__,rbuf[5], rbuf[6], rbuf[7], rbuf[8]); + } + + input_sync(sensor->input_dev); + + memcpy(g_akm_rbuf, rbuf, 12); //used for ECS_IOCTL_GET_ACCEL +} + + + +static int compass_dev_open(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + int result = 0; + DBG("%s\n",__func__); + + return result; +} + + +static int compass_dev_release(struct inode *inode, struct file *file) +{ +#ifdef SENSOR_DEBUG_TYPE + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(this_client); +#endif + int result = 0; + DBG("%s\n",__func__); + + return result; +} + +static int compass_akm_set_mode(struct i2c_client *client, char mode) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + int result = 0; + + switch(mode & 0x0f) + { + case AK8963_MODE_SNG_MEASURE: + case AK8963_MODE_SELF_TEST: + case AK8963_MODE_FUSE_ACCESS: + if(sensor->status_cur == SENSOR_OFF) + { + if(sensor->pdata->irq_enable) + { + //DBG("%s:enable irq=%d\n",__func__,client->irq); + //enable_irq(client->irq); + } + else + { + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + + sensor->status_cur = SENSOR_ON; + } + + break; + + case AK8963_MODE_POWERDOWN: + if(sensor->status_cur == SENSOR_ON) + { + if(sensor->pdata->irq_enable) + { + //DBG("%s:disable irq=%d\n",__func__,client->irq); + //disable_irq_nosync(client->irq);//disable irq + } + else + cancel_delayed_work_sync(&sensor->delaywork); + + sensor->status_cur = SENSOR_OFF; + } + break; + + } + + switch(mode & 0x0f) + { + case AK8963_MODE_SNG_MEASURE: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8963_MODE_SELF_TEST: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8963_MODE_FUSE_ACCESS: + result = sensor_write_reg(client, sensor->ops->ctrl_reg, mode); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + break; + case AK8963_MODE_POWERDOWN: + /* Set powerdown mode */ + result = sensor_write_reg(client, sensor->ops->ctrl_reg, AK8963_MODE_POWERDOWN); + if(result) + printk("%s:i2c error,mode=%d\n",__func__,mode); + udelay(100); + break; + default: + printk("%s: Unknown mode(%d)", __func__, mode); + result = -EINVAL; + break; + } + DBG("%s:mode=0x%x\n",__func__,mode); + return result; + +} + +static int compass_akm_reset(struct i2c_client *client) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + int result = 0; + + if(sensor->pdata->reset_pin > 0) + { + gpio_direction_output(sensor->pdata->reset_pin, GPIO_LOW); + udelay(10); + gpio_direction_output(sensor->pdata->reset_pin, GPIO_HIGH); + } + else + { + /* Set measure mode */ + result = sensor_write_reg(client, AK8963_REG_CNTL2, AK8963_MODE_SNG_MEASURE); + if(result) + printk("%s:fail to Set measure mode\n",__func__); + } + + udelay(100); + + return result; + +} + + + +static int compass_akm_get_openstatus(void) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) != 0)); + return atomic_read(&sensor->flags.open_flag); +} + +static int compass_akm_get_closestatus(void) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) <= 0)); + return atomic_read(&sensor->flags.open_flag); +} + + +/* ioctl - I/O control */ +static long compass_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + struct i2c_client *client = this_client; + void __user *argp = (void __user *)arg; + int result = 0; + struct akm_platform_data compass; + + /* NOTE: In this function the size of "char" should be 1-byte. */ + char compass_data[SENSOR_DATA_SIZE]; /* for GETDATA */ + char rwbuf[RWBUF_SIZE]; /* for READ/WRITE */ + char mode; /* for SET_MODE*/ + int value[12]; /* for SET_YPR */ + int status; /* for OPEN/CLOSE_STATUS */ + int ret = -1; /* Return value. */ + + //int8_t sensor_buf[SENSOR_DATA_SIZE]; /* for GETDATA */ + //int32_t ypr_buf[YPR_DATA_SIZE]; /* for SET_YPR */ + int16_t acc_buf[3]; /* for GET_ACCEL */ + int64_t delay[AKM_NUM_SENSORS]; /* for GET_DELAY */ + + char layout; /* for GET_LAYOUT */ + char outbit; /* for GET_OUTBIT */ + + switch (cmd) { + case ECS_IOCTL_WRITE: + case ECS_IOCTL_READ: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) { + return -EFAULT; + } + break; + case ECS_IOCTL_SET_MODE: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&mode, argp, sizeof(mode))) { + return -EFAULT; + } + break; + case ECS_IOCTL_SET_YPR: + if (argp == NULL) { + return -EINVAL; + } + if (copy_from_user(&value, argp, sizeof(value))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GETDATA: + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + case ECS_IOCTL_GET_DELAY: + case ECS_IOCTL_GET_LAYOUT: + case ECS_IOCTL_GET_OUTBIT: + case ECS_IOCTL_GET_ACCEL: + /* Just check buffer pointer */ + if (argp == NULL) { + printk("%s:invalid argument\n",__func__); + return -EINVAL; + } + break; + default: + break; + } + + switch (cmd) { + case ECS_IOCTL_WRITE: + DBG("%s:ECS_IOCTL_WRITE start\n",__func__); + mutex_lock(&sensor->operation_mutex); + if ((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) { + mutex_unlock(&sensor->operation_mutex); + return -EINVAL; + } + ret = sensor_tx_data(client, &rwbuf[1], rwbuf[0]); + if (ret < 0) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fait to tx data\n",__func__); + return ret; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_READ: + DBG("%s:ECS_IOCTL_READ start\n",__func__); + mutex_lock(&sensor->operation_mutex); + if ((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:data is error\n",__func__); + return -EINVAL; + } + ret = sensor_rx_data(client, &rwbuf[1], rwbuf[0]); + if (ret < 0) { + mutex_unlock(&sensor->operation_mutex); + printk("%s:fait to rx data\n",__func__); + return ret; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_SET_MODE: + DBG("%s:ECS_IOCTL_SET_MODE start\n",__func__); + mutex_lock(&sensor->operation_mutex); + if(sensor->ops->ctrl_data != mode) + { + ret = compass_akm_set_mode(client, mode); + if (ret < 0) { + printk("%s:fait to set mode\n",__func__); + mutex_unlock(&sensor->operation_mutex); + return ret; + } + + sensor->ops->ctrl_data = mode; + } + mutex_unlock(&sensor->operation_mutex); + break; + case ECS_IOCTL_GETDATA: + DBG("%s:ECS_IOCTL_GETDATA start\n",__func__); + mutex_lock(&sensor->data_mutex); + memcpy(compass_data, sensor->sensor_data, SENSOR_DATA_SIZE); //get data from buffer + mutex_unlock(&sensor->data_mutex); + break; + case ECS_IOCTL_SET_YPR: + DBG("%s:ECS_IOCTL_SET_YPR start\n",__func__); + mutex_lock(&sensor->data_mutex); + compass_set_YPR(value); + mutex_unlock(&sensor->data_mutex); + break; + case ECS_IOCTL_GET_OPEN_STATUS: + status = compass_akm_get_openstatus(); + DBG("%s:openstatus=%d\n",__func__,status); + break; + case ECS_IOCTL_GET_CLOSE_STATUS: + status = compass_akm_get_closestatus(); + DBG("%s:closestatus=%d\n",__func__,status); + break; + case ECS_IOCTL_GET_DELAY: + DBG("%s:ECS_IOCTL_GET_DELAY start\n",__func__); + mutex_lock(&sensor->operation_mutex); + delay[0] = sensor->flags.delay; + delay[1] = sensor->flags.delay; + delay[2] = sensor->flags.delay; + mutex_unlock(&sensor->operation_mutex); + break; + + case ECS_IOCTL_GET_PLATFORM_DATA: + DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__); + memcpy(compass.m_layout, sensor->pdata->m_layout, sizeof(sensor->pdata->m_layout)); + memcpy(compass.project_name, sensor->pdata->project_name, sizeof(sensor->pdata->project_name)); + ret = copy_to_user(argp, &compass, sizeof(compass)); + if(ret < 0) + { + printk("%s:error,ret=%d\n",__FUNCTION__, ret); + return ret; + } + break; + case ECS_IOCTL_GET_LAYOUT: + DBG("%s:ECS_IOCTL_GET_LAYOUT start\n",__func__); + layout = 1; //sensor->pdata->layout; + break; + case ECS_IOCTL_GET_OUTBIT: + DBG("%s:ECS_IOCTL_GET_OUTBIT start\n",__func__); + outbit = 1; //sensor->pdata->outbit; + break; + case ECS_IOCTL_RESET: + DBG("%s:ECS_IOCTL_RESET start\n",__func__); + ret = compass_akm_reset(client); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_GET_ACCEL: + DBG("%s:ECS_IOCTL_GET_ACCEL start,no accel data\n",__func__); + mutex_lock(&sensor->operation_mutex); + acc_buf[0] = g_akm_rbuf[6]; + acc_buf[1] = g_akm_rbuf[7]; + acc_buf[2] = g_akm_rbuf[8]; + mutex_unlock(&sensor->operation_mutex); + break; + + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_READ: + if (copy_to_user(argp, &rwbuf, rwbuf[0]+1)) { + return -EFAULT; + } + break; + case ECS_IOCTL_GETDATA: + if (copy_to_user(argp, &compass_data, sizeof(compass_data))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + if (copy_to_user(argp, &status, sizeof(status))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GET_DELAY: + if (copy_to_user(argp, &delay, sizeof(delay))) { + return -EFAULT; + } + break; + case ECS_IOCTL_GET_LAYOUT: + if (copy_to_user(argp, &layout, sizeof(layout))) { + printk("%s:error:%d\n",__FUNCTION__,__LINE__); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OUTBIT: + if (copy_to_user(argp, &outbit, sizeof(outbit))) { + printk("%s:error:%d\n",__FUNCTION__,__LINE__); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_ACCEL: + if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) { + printk("%s:error:%d\n",__FUNCTION__,__LINE__); + return -EFAULT; + } + break; + default: + break; + } + + return result; +} + +static struct file_operations compass_dev_fops = +{ + .owner = THIS_MODULE, + .open = compass_dev_open, + .release = compass_dev_release, + .unlocked_ioctl = compass_dev_ioctl, +}; + + +static struct miscdevice compass_dev_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "akm8963_dev", + .fops = &compass_dev_fops, +}; + +struct sensor_operate compass_akm8963_ops = { + .name = "akm8963", + .type = SENSOR_TYPE_COMPASS, //it is important + .id_i2c = COMPASS_ID_AK8963, + .read_reg = AK8963_REG_ST1, //read data + .read_len = SENSOR_DATA_SIZE, //data length + .id_reg = AK8963_REG_WIA, //read id + .id_data = AK8963_DEVICE_ID, + .precision = 8, //12 bits + .ctrl_reg = AK8963_REG_CNTL1, //enable or disable + .int_status_reg = SENSOR_UNKNOW_DATA, //not exist + .range = {-0xffff,0xffff}, + .trig = IRQF_TRIGGER_RISING, //if LEVEL interrupt then IRQF_ONESHOT + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, + .misc_dev = NULL, //private misc support +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +static struct sensor_operate *compass_get_ops(void) +{ + return &compass_akm8963_ops; +} + + +static int __init compass_akm8963_init(void) +{ + struct sensor_operate *ops = compass_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, compass_get_ops); + + result = misc_register(&compass_dev_device); + if (result < 0) { + printk("%s:fail to register misc device %s\n", __func__, compass_dev_device.name); + goto error; + } +error: + return result; +} + +static void __exit compass_akm8963_exit(void) +{ + struct sensor_operate *ops = compass_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, compass_get_ops); +} + + +module_init(compass_akm8963_init); +module_exit(compass_akm8963_exit); + + diff --git a/drivers/input/sensors/compass/ak8975.c b/drivers/input/sensors/compass/ak8975.c index 3d2448f5893f..cecf15fb5f5a 100755 --- a/drivers/input/sensors/compass/ak8975.c +++ b/drivers/input/sensors/compass/ak8975.c @@ -30,7 +30,7 @@ #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif -#include + #include #define SENSOR_DATA_SIZE 8 @@ -42,17 +42,78 @@ #define DBG(x...) #endif +/*! \name AK8975 operation mode + \anchor AK8975_Mode + Defines an operation mode of the AK8975.*/ +/*! @{*/ +#define AK8975_MODE_SNG_MEASURE 0x01 +#define AK8975_MODE_SELF_TEST 0x08 +#define AK8975_MODE_FUSE_ACCESS 0x0F +#define AK8975_MODE_POWERDOWN 0x00 +/*! @}*/ + +#define SENSOR_DATA_SIZE 8 /* Rx buffer size, i.e from ST1 to ST2 */ +#define RWBUF_SIZE 16 /* Read/Write buffer size.*/ + + +/*! \name AK8975 register address +\anchor AK8975_REG +Defines a register address of the AK8975.*/ +/*! @{*/ +#define AK8975_REG_WIA 0x00 +#define AK8975_REG_INFO 0x01 +#define AK8975_REG_ST1 0x02 +#define AK8975_REG_HXL 0x03 +#define AK8975_REG_HXH 0x04 +#define AK8975_REG_HYL 0x05 +#define AK8975_REG_HYH 0x06 +#define AK8975_REG_HZL 0x07 +#define AK8975_REG_HZH 0x08 +#define AK8975_REG_ST2 0x09 +#define AK8975_REG_CNTL 0x0A +#define AK8975_REG_RSV 0x0B +#define AK8975_REG_ASTC 0x0C +#define AK8975_REG_TS1 0x0D +#define AK8975_REG_TS2 0x0E +#define AK8975_REG_I2CDIS 0x0F +/*! @}*/ + +/*! \name AK8975 fuse-rom address +\anchor AK8975_FUSE +Defines a read-only address of the fuse ROM of the AK8975.*/ +/*! @{*/ +#define AK8975_FUSE_ASAX 0x10 +#define AK8975_FUSE_ASAY 0x11 +#define AK8975_FUSE_ASAZ 0x12 +/*! @}*/ + +#define AK8975_INFO_DATA (0x01<<3) + + +#define COMPASS_IOCTL_MAGIC 'c' + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_WRITE _IOW(COMPASS_IOCTL_MAGIC, 0x01, char*) +#define ECS_IOCTL_READ _IOWR(COMPASS_IOCTL_MAGIC, 0x02, char*) +#define ECS_IOCTL_RESET _IO(COMPASS_IOCTL_MAGIC, 0x03) /* NOT used in AK8975 */ +#define ECS_IOCTL_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x04, short) +#define ECS_IOCTL_GETDATA _IOR(COMPASS_IOCTL_MAGIC, 0x05, char[SENSOR_DATA_SIZE]) +#define ECS_IOCTL_SET_YPR _IOW(COMPASS_IOCTL_MAGIC, 0x06, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x07, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(COMPASS_IOCTL_MAGIC, 0x08, int) +#define ECS_IOCTL_GET_LAYOUT _IOR(COMPASS_IOCTL_MAGIC, 0x09, char) +#define ECS_IOCTL_GET_ACCEL _IOR(COMPASS_IOCTL_MAGIC, 0x0A, short[3]) +#define ECS_IOCTL_GET_OUTBIT _IOR(COMPASS_IOCTL_MAGIC, 0x0B, char) +#define ECS_IOCTL_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x30, short) +#define ECS_IOCTL_GET_PROJECT_NAME _IOR(COMPASS_IOCTL_MAGIC, 0x0D, char[64]) +#define ECS_IOCTL_GET_MATRIX _IOR(COMPASS_IOCTL_MAGIC, 0x0E, short [4][3][3]) +#define ECS_IOCTL_GET_PLATFORM_DATA _IOR(COMPASS_IOCTL_MAGIC, 0x0E, struct akm_platform_data) #define AK8975_DEVICE_ID 0x48 static struct i2c_client *this_client; -static atomic_t m_flag; -static atomic_t a_flag; -static atomic_t mv_flag; -static atomic_t open_flag; -static short akmd_delay = 100; -static DECLARE_WAIT_QUEUE_HEAD(open_wq); + /****************operate according to sensor chip:start************/ @@ -89,6 +150,7 @@ static int sensor_init(struct i2c_client *client) struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); int result = 0; + int info = 0; this_client = client; @@ -100,15 +162,15 @@ static int sensor_init(struct i2c_client *client) } sensor->status_cur = SENSOR_OFF; -#if 0 - sensor->ops->ctrl_data = 0; - result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); - if(result) + + info = sensor_read_reg(client, AK8975_REG_INFO); + if((info & (0x0f<<3)) != AK8975_INFO_DATA) + { - printk("%s:line=%d,error\n",__func__,__LINE__); - return result; + printk("%s:info=0x%x,it is not %s\n",__func__, info, sensor->ops->name); + result = -1; } -#endif + DBG("%s:status_cur=%d\n",__func__, sensor->status_cur); return result; } @@ -191,7 +253,7 @@ static int sensor_report_value(struct i2c_client *client) #ifdef SENSOR_DEBUG_TYPE DBG("%s:",__func__); for(i=0; iops->read_len; i++) - DBG("%d,",buffer[i]); + DBG("0x%x,",buffer[i]); DBG("\n"); #endif @@ -220,7 +282,7 @@ static void compass_set_YPR(short *rbuf) (struct sensor_private_data *) i2c_get_clientdata(this_client); /* Report magnetic sensor information */ - if (atomic_read(&m_flag)) { + if (atomic_read(&sensor->flags.m_flag)) { input_report_abs(sensor->input_dev, ABS_RX, rbuf[0]); input_report_abs(sensor->input_dev, ABS_RY, rbuf[1]); input_report_abs(sensor->input_dev, ABS_RZ, rbuf[2]); @@ -229,7 +291,7 @@ static void compass_set_YPR(short *rbuf) } /* Report acceleration sensor information */ - if (atomic_read(&a_flag)) { + if (atomic_read(&sensor->flags.a_flag)) { input_report_abs(sensor->input_dev, ABS_X, rbuf[6]); input_report_abs(sensor->input_dev, ABS_Y, rbuf[7]); input_report_abs(sensor->input_dev, ABS_Z, rbuf[8]); @@ -239,7 +301,7 @@ static void compass_set_YPR(short *rbuf) } /* Report magnetic vector information */ - if (atomic_read(&mv_flag)) { + if (atomic_read(&sensor->flags.mv_flag)) { input_report_abs(sensor->input_dev, ABS_HAT0X, rbuf[9]); input_report_abs(sensor->input_dev, ABS_HAT0Y, rbuf[10]); input_report_abs(sensor->input_dev, ABS_BRAKE, rbuf[11]); @@ -251,131 +313,6 @@ static void compass_set_YPR(short *rbuf) } - -static int compass_aot_open(struct inode *inode, struct file *file) -{ -#ifdef SENSOR_DEBUG_TYPE - struct sensor_private_data* sensor = - (struct sensor_private_data *)i2c_get_clientdata(this_client); -#endif - int result = 0; - int flag = 0; - flag = atomic_read(&open_flag); - if(!flag) - { - atomic_set(&open_flag, 1); - wake_up(&open_wq); - } - - DBG("%s\n", __func__); - return result; -} - - -static int compass_aot_release(struct inode *inode, struct file *file) -{ -#ifdef SENSOR_DEBUG_TYPE - struct sensor_private_data* sensor = - (struct sensor_private_data *)i2c_get_clientdata(this_client); -#endif - //struct i2c_client *client = this_client; - int result = 0; - int flag = 0; - flag = atomic_read(&open_flag); - if(flag) - { - atomic_set(&open_flag, 0); - wake_up(&open_wq); - } - - DBG("%s\n", __func__); - return result; -} - - -/* ioctl - I/O control */ -static long compass_aot_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ -#ifdef SENSOR_DEBUG_TYPE - struct sensor_private_data* sensor = - (struct sensor_private_data *)i2c_get_clientdata(this_client); -#endif - void __user *argp = (void __user *)arg; - int result = 0; - short flag; - - switch (cmd) { - case ECS_IOCTL_APP_SET_MFLAG: - case ECS_IOCTL_APP_SET_AFLAG: - case ECS_IOCTL_APP_SET_MVFLAG: - if (copy_from_user(&flag, argp, sizeof(flag))) { - return -EFAULT; - } - if (flag < 0 || flag > 1) { - return -EINVAL; - } - break; - case ECS_IOCTL_APP_SET_DELAY: - if (copy_from_user(&flag, argp, sizeof(flag))) { - return -EFAULT; - } - break; - default: - break; - } - - switch (cmd) { - case ECS_IOCTL_APP_SET_MFLAG: - atomic_set(&m_flag, flag); - DBG("%s:ECS_IOCTL_APP_SET_MFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_GET_MFLAG: - flag = atomic_read(&m_flag); - DBG("%s:ECS_IOCTL_APP_GET_MFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_SET_AFLAG: - atomic_set(&a_flag, flag); - DBG("%s:ECS_IOCTL_APP_SET_AFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_GET_AFLAG: - flag = atomic_read(&a_flag); - DBG("%s:ECS_IOCTL_APP_GET_AFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_SET_MVFLAG: - atomic_set(&mv_flag, flag); - DBG("%s:ECS_IOCTL_APP_SET_MVFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_GET_MVFLAG: - flag = atomic_read(&mv_flag); - DBG("%s:ECS_IOCTL_APP_GET_MVFLAG,flag=%d\n", __func__,flag); - break; - case ECS_IOCTL_APP_SET_DELAY: - akmd_delay = flag; - break; - case ECS_IOCTL_APP_GET_DELAY: - flag = akmd_delay; - break; - default: - return -ENOTTY; - } - - switch (cmd) { - case ECS_IOCTL_APP_GET_MFLAG: - case ECS_IOCTL_APP_GET_AFLAG: - case ECS_IOCTL_APP_GET_MVFLAG: - case ECS_IOCTL_APP_GET_DELAY: - if (copy_to_user(argp, &flag, sizeof(flag))) { - return -EFAULT; - } - break; - default: - break; - } - - return result; -} - static int compass_dev_open(struct inode *inode, struct file *file) { #ifdef SENSOR_DEBUG_TYPE @@ -482,14 +419,16 @@ static int compass_akm_set_mode(struct i2c_client *client, char mode) static int compass_akm_get_openstatus(void) { - wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0)); - return atomic_read(&open_flag); + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) != 0)); + return atomic_read(&sensor->flags.open_flag); } static int compass_akm_get_closestatus(void) { - wait_event_interruptible(open_wq, (atomic_read(&open_flag) <= 0)); - return atomic_read(&open_flag); + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + wait_event_interruptible(sensor->flags.open_wq, (atomic_read(&sensor->flags.open_flag) <= 0)); + return atomic_read(&sensor->flags.open_flag); } @@ -497,11 +436,11 @@ static int compass_akm_get_closestatus(void) static long compass_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); + struct sensor_private_data* sensor = (struct sensor_private_data *)i2c_get_clientdata(this_client); struct i2c_client *client = this_client; void __user *argp = (void __user *)arg; int result = 0; - struct akm8975_platform_data compass; + struct akm_platform_data compass; /* NOTE: In this function the size of "char" should be 1-byte. */ char compass_data[SENSOR_DATA_SIZE];/* for GETDATA */ @@ -611,7 +550,7 @@ static long compass_dev_ioctl(struct file *file, DBG("%s:closestatus=%d\n",__func__,status); break; case ECS_IOCTL_GET_DELAY: - delay = akmd_delay; + delay = sensor->flags.delay; break; case ECS_IOCTL_GET_PLATFORM_DATA: DBG("%s:ECS_IOCTL_GET_PLATFORM_DATA start\n",__func__); @@ -658,25 +597,6 @@ static long compass_dev_ioctl(struct file *file, return result; } - -static struct file_operations compass_aot_fops = -{ - .owner = THIS_MODULE, - .unlocked_ioctl = compass_aot_ioctl, - .open = compass_aot_open, - .release = compass_aot_release, -}; - - - -static struct miscdevice compass_aot_device = -{ - .minor = MISC_DYNAMIC_MINOR, - .name = "akm8975_aot", - .fops = &compass_aot_fops, -}; - - static struct file_operations compass_dev_fops = { .owner = THIS_MODULE, @@ -693,7 +613,7 @@ static struct miscdevice compass_dev_device = .fops = &compass_dev_fops, }; -struct sensor_operate akm8975_akm8975_ops = { +struct sensor_operate compass_akm8975_ops = { .name = "akm8975", .type = SENSOR_TYPE_COMPASS, //it is important .id_i2c = COMPASS_ID_AK8975, @@ -703,13 +623,13 @@ struct sensor_operate akm8975_akm8975_ops = { .id_data = AK8975_DEVICE_ID, .precision = 8, //12 bits .ctrl_reg = AK8975_REG_CNTL, //enable or disable - .int_status_reg = SENSOR_UNKNOW_DATA, //not exist + .int_status_reg = SENSOR_UNKNOW_DATA, //not exist .range = {-0xffff,0xffff}, .trig = IRQF_TRIGGER_RISING, //if LEVEL interrupt then IRQF_ONESHOT .active = sensor_active, .init = sensor_init, .report = sensor_report_value, - .misc_dev = &compass_dev_device, //private misc support + .misc_dev = NULL, //private misc support }; /****************operate according to sensor chip:end************/ @@ -717,7 +637,7 @@ struct sensor_operate akm8975_akm8975_ops = { //function name should not be changed static struct sensor_operate *compass_get_ops(void) { - return &akm8975_akm8975_ops; + return &compass_akm8975_ops; } @@ -728,21 +648,12 @@ static int __init compass_akm8975_init(void) int type = ops->type; result = sensor_register_slave(type, NULL, NULL, compass_get_ops); - result = misc_register(&compass_aot_device); + result = misc_register(&compass_dev_device); if (result < 0) { - printk("%s:fail to register misc device %s\n", __func__, compass_aot_device.name); + printk("%s:fail to register misc device %s\n", __func__, compass_dev_device.name); goto error; } - - /* As default, report all information */ - atomic_set(&m_flag, 1); - atomic_set(&a_flag, 1); - atomic_set(&mv_flag, 1); - atomic_set(&open_flag, 0); - init_waitqueue_head(&open_wq); - - DBG("%s\n",__func__); -error: +error: return result; } diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c index c172a17c0147..7fa69e758c1d 100755 --- a/drivers/input/sensors/sensor-dev.c +++ b/drivers/input/sensors/sensor-dev.c @@ -31,7 +31,6 @@ #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif -#include #include #include @@ -43,7 +42,11 @@ #define DBG(x...) #endif -#define SENSOR_VERSION_AND_TIME "sensor-dev.c v1.1 add pressure and temperature support 2013-2-27" +#if 0 +sensor-dev.c v1.1 add pressure and temperature support 2013-2-27 +sensor-dev.c v1.2 add akm8963 support 2013-3-10 +#endif +#define SENSOR_VERSION_AND_TIME "sensor-dev.c v1.2 add akm8963 support 2013-3-10" struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES]; @@ -562,36 +565,122 @@ static int gsensor_class_init(void) static int compass_dev_open(struct inode *inode, struct file *file) { - //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; - //struct i2c_client *client = sensor->client; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + //struct i2c_client *client = sensor->client; + int result = 0; - - //to do + int flag = 0; + flag = atomic_read(&sensor->flags.open_flag); + if(!flag) + { + atomic_set(&sensor->flags.open_flag, 1); + wake_up(&sensor->flags.open_wq); + } + + DBG("%s\n", __func__); return result; } + static int compass_dev_release(struct inode *inode, struct file *file) { - //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; - //struct i2c_client *client = sensor->client; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + //struct i2c_client *client = sensor->client; + //void __user *argp = (void __user *)arg; int result = 0; - - //to do + int flag = 0; + flag = atomic_read(&sensor->flags.open_flag); + if(flag) + { + atomic_set(&sensor->flags.open_flag, 0); + wake_up(&sensor->flags.open_wq); + } + + DBG("%s\n", __func__); return result; } + /* ioctl - I/O control */ static long compass_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - //struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; - //struct i2c_client *client = sensor->client; - //void __user *argp = (void __user *)arg; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; int result = 0; + short flag; + + switch (cmd) { + case ECS_IOCTL_APP_SET_MFLAG: + case ECS_IOCTL_APP_SET_AFLAG: + case ECS_IOCTL_APP_SET_MVFLAG: + if (copy_from_user(&flag, argp, sizeof(flag))) { + return -EFAULT; + } + if (flag < 0 || flag > 1) { + return -EINVAL; + } + break; + case ECS_IOCTL_APP_SET_DELAY: + if (copy_from_user(&flag, argp, sizeof(flag))) { + return -EFAULT; + } + break; + default: + break; + } - //to do + switch (cmd) { + case ECS_IOCTL_APP_SET_MFLAG: + atomic_set(&sensor->flags.m_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_MFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_MFLAG: + flag = atomic_read(&sensor->flags.m_flag); + DBG("%s:ECS_IOCTL_APP_GET_MFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_AFLAG: + atomic_set(&sensor->flags.a_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_AFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_AFLAG: + flag = atomic_read(&sensor->flags.a_flag); + DBG("%s:ECS_IOCTL_APP_GET_AFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_MVFLAG: + atomic_set(&sensor->flags.mv_flag, flag); + DBG("%s:ECS_IOCTL_APP_SET_MVFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_GET_MVFLAG: + flag = atomic_read(&sensor->flags.mv_flag); + DBG("%s:ECS_IOCTL_APP_GET_MVFLAG,flag=%d\n", __func__,flag); + break; + case ECS_IOCTL_APP_SET_DELAY: + sensor->flags.delay = flag; + break; + case ECS_IOCTL_APP_GET_DELAY: + flag = sensor->flags.delay; + break; + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_APP_GET_MFLAG: + case ECS_IOCTL_APP_GET_AFLAG: + case ECS_IOCTL_APP_GET_MVFLAG: + case ECS_IOCTL_APP_GET_DELAY: + if (copy_to_user(argp, &flag, sizeof(flag))) { + return -EFAULT; + } + break; + default: + break; + } + return result; } @@ -1399,6 +1488,12 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) goto out_free_memory; } + if(pdata->reset_pin) + gpio_request(pdata->reset_pin,"sensor_reset_pin"); + + if(pdata->power_pin) + gpio_request(pdata->power_pin,"sensor_power_pin"); + memset(&(sensor->axis), 0, sizeof(struct sensor_axis) ); atomic_set(&(sensor->data_ready), 0); init_waitqueue_head(&(sensor->data_ready_wq)); @@ -1407,6 +1502,14 @@ int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) mutex_init(&sensor->sensor_mutex); mutex_init(&sensor->i2c_mutex); + /* As default, report all information */ + atomic_set(&sensor->flags.m_flag, 1); + atomic_set(&sensor->flags.a_flag, 1); + atomic_set(&sensor->flags.mv_flag, 1); + atomic_set(&sensor->flags.open_flag, 0); + init_waitqueue_head(&sensor->flags.open_wq); + sensor->flags.delay = 100; + sensor->status_cur = SENSOR_OFF; sensor->axis.x = 0; sensor->axis.y = 0; @@ -1559,7 +1662,7 @@ out_input_register_device_failed: out_free_memory: kfree(sensor); out_no_free: - dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + dev_err(&client->adapter->dev, "%s failed %d\n\n", __func__, result); return result; } @@ -1603,7 +1706,8 @@ static const struct i2c_device_id sensor_id[] = { {"gs_mxc6225", ACCEL_ID_MXC6225}, /*compass*/ {"compass", COMPASS_ID_ALL}, - {"ak8975", COMPASS_ID_AK8975}, + {"ak8975", COMPASS_ID_AK8975}, + {"ak8963", COMPASS_ID_AK8963}, {"mmc314x", COMPASS_ID_MMC314X}, /*gyroscope*/ {"gyro", GYRO_ID_ALL}, diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h index 980069ae7f23..236fe8e97d8b 100755 --- a/include/linux/sensor-dev.h +++ b/include/linux/sensor-dev.h @@ -58,6 +58,7 @@ enum sensor_id { COMPASS_ID_ALL, COMPASS_ID_AK8975, + COMPASS_ID_AK8963, COMPASS_ID_AK8972, COMPASS_ID_AMI30X, COMPASS_ID_AMI306, @@ -104,6 +105,16 @@ struct sensor_axis { int z; }; +struct sensor_flag { + atomic_t a_flag; + atomic_t m_flag; + atomic_t mv_flag; + atomic_t open_flag; + long long delay; + wait_queue_head_t open_wq; +}; + + struct sensor_operate { char *name; int type; @@ -148,6 +159,7 @@ struct sensor_private_data { int status_cur; int start_count; int devid; + struct sensor_flag flags; struct i2c_device_id *i2c_id; struct sensor_platform_data *pdata; struct sensor_operate *ops; @@ -169,27 +181,45 @@ extern int sensor_unregister_slave(int type,struct i2c_client *client, struct sensor_operate *(*get_sensor_ops)(void)); -#define GSENSOR_IO 0xA1 +#define GSENSOR_IOCTL_MAGIC 'a' #define GBUFF_SIZE 12 /* Rx buffer size */ /* IOCTLs for MMA8452 library */ -#define GSENSOR_IOCTL_INIT _IO(GSENSOR_IO, 0x01) -#define GSENSOR_IOCTL_RESET _IO(GSENSOR_IO, 0x04) -#define GSENSOR_IOCTL_CLOSE _IO(GSENSOR_IO, 0x02) -#define GSENSOR_IOCTL_START _IO(GSENSOR_IO, 0x03) -#define GSENSOR_IOCTL_GETDATA _IOR(GSENSOR_IO, 0x08, char[GBUFF_SIZE+1]) +#define GSENSOR_IOCTL_INIT _IO(GSENSOR_IOCTL_MAGIC, 0x01) +#define GSENSOR_IOCTL_RESET _IO(GSENSOR_IOCTL_MAGIC, 0x04) +#define GSENSOR_IOCTL_CLOSE _IO(GSENSOR_IOCTL_MAGIC, 0x02) +#define GSENSOR_IOCTL_START _IO(GSENSOR_IOCTL_MAGIC, 0x03) +#define GSENSOR_IOCTL_GETDATA _IOR(GSENSOR_IOCTL_MAGIC, 0x08, char[GBUFF_SIZE+1]) +/* IOCTLs for APPs */ +#define GSENSOR_IOCTL_APP_SET_RATE _IOW(GSENSOR_IOCTL_MAGIC, 0x10, char) + + +#define COMPASS_IOCTL_MAGIC 'c' /* IOCTLs for APPs */ -#define GSENSOR_IOCTL_APP_SET_RATE _IOW(GSENSOR_IO, 0x10, char) +#define ECS_IOCTL_APP_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x12, short) +#define ECS_IOCTL_APP_SET_AFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x13, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x15, short)/* NOT use */ +#define ECS_IOCTL_APP_GET_TFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x16, short)/* NOT use */ +#define ECS_IOCTL_APP_RESET_PEDOMETER _IOW(COMPASS_IOCTL_MAGIC, 0x17) /* NOT use */ +#define ECS_IOCTL_APP_SET_DELAY _IOW(COMPASS_IOCTL_MAGIC, 0x18, short) +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x19, short) +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x1A, short) +#define ECS_IOCTL_APP_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x1B, short) + + #define LIGHTSENSOR_IOCTL_MAGIC 'l' #define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *) -#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) -#define LIGHTSENSOR_IOCTL_DISABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *) +#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *) +#define LIGHTSENSOR_IOCTL_DISABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, int *) -#define PSENSOR_IOCTL_MAGIC 'c' -#define PSENSOR_IOCTL_GET_ENABLED _IOR(PSENSOR_IOCTL_MAGIC, 1, int *) -#define PSENSOR_IOCTL_ENABLE _IOW(PSENSOR_IOCTL_MAGIC, 2, int *) +#define PSENSOR_IOCTL_MAGIC 'p' +#define PSENSOR_IOCTL_GET_ENABLED _IOR(PSENSOR_IOCTL_MAGIC, 1, int *) +#define PSENSOR_IOCTL_ENABLE _IOW(PSENSOR_IOCTL_MAGIC, 2, int *) #define PSENSOR_IOCTL_DISABLE _IOW(PSENSOR_IOCTL_MAGIC, 3, int *)