From 9519fc2cb1daeb592094e299e5b7c538ae7752c1 Mon Sep 17 00:00:00 2001 From: terry Date: Fri, 19 Jul 2019 14:39:01 +0800 Subject: [PATCH] Gsensor: add kxtj3 driver support Signed-off-by: Nick Xie [sw0312.kim: pick khadas 3-axis sensor commit from https://github.com/khadas/linux/commit/0ff70f7087ecad3d28b06c8632ea93fd8cd056af ] Signed-off-by: Seung-Woo Kim Change-Id: Id6166357a6816a3bca1d77072dcfc0ea9499aafc --- arch/arm64/boot/dts/amlogic/kvim3_linux.dts | 11 + arch/arm64/configs/kvims_defconfig | 1 + drivers/input/Kconfig | 2 + drivers/input/Makefile | 1 + drivers/input/sensors/Kconfig | 15 + drivers/input/sensors/Makefile | 6 + drivers/input/sensors/accel/Kconfig | 21 + drivers/input/sensors/accel/Makefile | 2 + drivers/input/sensors/accel/kxtj3.c | 326 +++++ drivers/input/sensors/sensor-dev.c | 1852 +++++++++++++++++++++++++++ drivers/input/sensors/sensor-i2c.c | 241 ++++ include/linux/sensor-dev.h | 263 ++++ 12 files changed, 2741 insertions(+) create mode 100755 drivers/input/sensors/Kconfig create mode 100755 drivers/input/sensors/Makefile create mode 100755 drivers/input/sensors/accel/Kconfig create mode 100755 drivers/input/sensors/accel/Makefile create mode 100755 drivers/input/sensors/accel/kxtj3.c create mode 100755 drivers/input/sensors/sensor-dev.c create mode 100755 drivers/input/sensors/sensor-i2c.c create mode 100755 include/linux/sensor-dev.h diff --git a/arch/arm64/boot/dts/amlogic/kvim3_linux.dts b/arch/arm64/boot/dts/amlogic/kvim3_linux.dts index 8961974..2c18f54 100644 --- a/arch/arm64/boot/dts/amlogic/kvim3_linux.dts +++ b/arch/arm64/boot/dts/amlogic/kvim3_linux.dts @@ -956,6 +956,17 @@ fan,trig_temp_level2 = <70>; hwver = "VIM3.V11"; /* Will be updated in uboot. */ }; + + khadas-kxtj3 { + compatible = "kxtj3"; + reg = <0x0E>; + type = <2>; + layout = <2>; + irq_enable = <0>; + poll_delay_ms = <30>; + irq-gpio = <&gpio_ao GPIOAO_9 IRQ_TYPE_EDGE_RISING>; + status = "okay"; + }; }; &audiobus { diff --git a/arch/arm64/configs/kvims_defconfig b/arch/arm64/configs/kvims_defconfig index 2563bb5..b66806f 100644 --- a/arch/arm64/configs/kvims_defconfig +++ b/arch/arm64/configs/kvims_defconfig @@ -512,6 +512,7 @@ CONFIG_JOYSTICK_XPAD=y CONFIG_JOYSTICK_XPAD_FF=y CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_SENSOR_DEVICE=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_GAMEPORT_NS558=m diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 34ffa02..06b0c36 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -212,6 +212,8 @@ source "drivers/input/tablet/Kconfig" source "drivers/input/touchscreen/Kconfig" +source "drivers/input/sensors/Kconfig" + source "drivers/input/misc/Kconfig" source "drivers/input/rmi4/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 6a3281c..e4a4652 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_MOUSE) += mouse/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ +obj-$(CONFIG_SENSOR_DEVICE) += sensors/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/drivers/input/sensors/Kconfig b/drivers/input/sensors/Kconfig new file mode 100755 index 0000000..5a82763 --- /dev/null +++ b/drivers/input/sensors/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# all sensors drivers configuration +# + +comment "handle all sensors" + +menuconfig SENSOR_DEVICE + tristate "handle accel" + default n + +if SENSOR_DEVICE +source "drivers/input/sensors/accel/Kconfig" + +endif diff --git a/drivers/input/sensors/Makefile b/drivers/input/sensors/Makefile new file mode 100755 index 0000000..61c8687 --- /dev/null +++ b/drivers/input/sensors/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# sensor drivers +obj-$(CONFIG_GSENSOR_DEVICE) += accel/ + +obj-$(CONFIG_SENSOR_DEVICE) += sensor-i2c.o +obj-$(CONFIG_SENSOR_DEVICE) += sensor-dev.o diff --git a/drivers/input/sensors/accel/Kconfig b/drivers/input/sensors/accel/Kconfig new file mode 100755 index 0000000..012c156 --- /dev/null +++ b/drivers/input/sensors/accel/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# gsensor drivers configuration +# + +menuconfig GSENSOR_DEVICE + tristate "g_sensor device support" + default y + help + Enable this to be able to choose the drivers for controlling the + g_sensor on some platforms, for example on PDAs. + +if GSENSOR_DEVICE +config GS_KXTJ3 + bool "gsensor kxtj3" + default y + help + To have support for your specific gsesnor you will have to + select the proper drivers which depend on this option. + +endif diff --git a/drivers/input/sensors/accel/Makefile b/drivers/input/sensors/accel/Makefile new file mode 100755 index 0000000..69babf04 --- /dev/null +++ b/drivers/input/sensors/accel/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_GS_KXTJ3) += kxtj3.o diff --git a/drivers/input/sensors/accel/kxtj3.c b/drivers/input/sensors/accel/kxtj3.c new file mode 100755 index 0000000..41fd910 --- /dev/null +++ b/drivers/input/sensors/accel/kxtj3.c @@ -0,0 +1,326 @@ +/* drivers/input/sensors/access/kxtj3.c + * + * Copyright (C) 2019 Khadas. + * Author: Waylon + * + * 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 KXTJ3_DEVID 0x35 //chip id +#define KXTJ3_RANGE (2 * 16384) + +#define KXTJ3_XOUT_HPF_L (0x00) /* 0000 0000 */ +#define KXTJ3_XOUT_HPF_H (0x01) /* 0000 0001 */ +#define KXTJ3_YOUT_HPF_L (0x02) /* 0000 0010 */ +#define KXTJ3_YOUT_HPF_H (0x03) /* 0000 0011 */ +#define KXTJ3_ZOUT_HPF_L (0x04) /* 0001 0100 */ +#define KXTJ3_ZOUT_HPF_H (0x05) /* 0001 0101 */ +#define KXTJ3_XOUT_L (0x06) /* 0000 0110 */ +#define KXTJ3_XOUT_H (0x07) /* 0000 0111 */ +#define KXTJ3_YOUT_L (0x08) /* 0000 1000 */ +#define KXTJ3_YOUT_H (0x09) /* 0000 1001 */ +#define KXTJ3_ZOUT_L (0x0A) /* 0001 1010 */ +#define KXTJ3_ZOUT_H (0x0B) /* 0001 1011 */ +#define KXTJ3_ST_RESP (0x0C) /* 0000 1100 */ +#define KXTJ3_WHO_AM_I (0x0F) /* 0000 1111 */ +#define KXTJ3_TILT_POS_CUR (0x10) /* 0001 0000 */ +#define KXTJ3_TILT_POS_PRE (0x11) /* 0001 0001 */ +#define KXTJ3_INT_SRC_REG1 (0x15) /* 0001 0101 */ +#define KXTJ3_INT_SRC_REG2 (0x16) /* 0001 0110 */ +#define KXTJ3_STATUS_REG (0x18) /* 0001 1000 */ +#define KXTJ3_INT_REL (0x1A) /* 0001 1010 */ +#define KXTJ3_CTRL_REG1 (0x1B) /* 0001 1011 */ +#define KXTJ3_CTRL_REG2 (0x1C) /* 0001 1100 */ +#define KXTJ3_CTRL_REG3 (0x1D) /* 0001 1101 */ +#define KXTJ3_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ +#define KXTJ3_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ +#define KXTJ3_INT_CTRL_REG3 (0x20) /* 0010 0000 */ +#define KXTJ3_DATA_CTRL_REG (0x21) /* 0010 0001 */ +#define KXTJ3_TILT_TIMER (0x28) /* 0010 1000 */ +#define KXTJ3_WUF_TIMER (0x29) /* 0010 1001 */ +#define KXTJ3_TDT_TIMER (0x2B) /* 0010 1011 */ +#define KXTJ3_TDT_H_THRESH (0x2C) /* 0010 1100 */ +#define KXTJ3_TDT_L_THRESH (0x2D) /* 0010 1101 */ +#define KXTJ3_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ +#define KXTJ3_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ +#define KXTJ3_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ +#define KXTJ3_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ +#define KXTJ3_WUF_THRESH (0x5A) /* 0101 1010 */ +#define KXTJ3_TILT_ANGLE (0x5C) /* 0101 1100 */ +#define KXTJ3_HYST_SET (0x5F) /* 0101 1111 */ + +/* CONTROL REGISTER 1 BITS */ +#define KXTJ3_DISABLE 0x7F +#define KXTJ3_ENABLE (1 << 7) +#define KXTJ3_INT_ENABLE (1 << 5) +/* INPUT_ABS CONSTANTS */ +#define FUZZ 3 +#define FLAT 3 +/* RESUME STATE INDICES */ +#define RES_DATA_CTRL 0 +#define RES_CTRL_REG1 1 +#define RES_INT_CTRL1 2 +#define RESUME_ENTRIES 3 + +/* CTRL_REG1: set resolution, g-range, data ready enable */ +/* Output resolution: 8-bit valid or 12-bit valid */ +#define KXTJ3_RES_8BIT 0 +#define KXTJ3_RES_12BIT (1 << 6) +/* Output g-range: +/-2g, 4g, or 8g */ +#define KXTJ3_G_2G 0 +#define KXTJ3_G_4G (1 << 3) +#define KXTJ3_G_8G (1 << 4) + +/* DATA_CTRL_REG: controls the output data rate of the part */ +#define KXTJ3_ODR12_5F 0 +#define KXTJ3_ODR25F 1 +#define KXTJ3_ODR50F 2 +#define KXTJ3_ODR100F 3 +#define KXTJ3_ODR200F 4 +#define KXTJ3_ODR400F 5 +#define KXTJ3_ODR800F 6 + +/* kxtj3 */ +#define KXTJ3_PRECISION 12 +#define KXTJ3_BOUNDARY (0x1 << (KXTJ3_PRECISION - 1)) +#define KXTJ3_GRAVITY_STEP KXTJ3_RANGE / KXTJ3_BOUNDARY + + +/****************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; + int status = 0; + + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); + + //register setting according to chip datasheet + if(enable) + { + status = KXTJ3_ENABLE; //kxtj3 + sensor->ops->ctrl_data |= status; + } + else + { + status = ~KXTJ3_ENABLE; //kxtj3 + sensor->ops->ctrl_data &= status; + } + + 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; + + result = sensor->ops->active(client,0,0); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + sensor->status_cur = SENSOR_OFF; + + result = sensor_write_reg(client, KXTJ3_DATA_CTRL_REG, KXTJ3_ODR400F); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + + if(sensor->pdata->irq_enable) //open interrupt + { + result = sensor_write_reg(client, KXTJ3_INT_CTRL_REG1, 0x34);//enable int,active high,need read INT_REL + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + } + + sensor->ops->ctrl_data = (KXTJ3_RES_12BIT | KXTJ3_G_2G); + if(sensor->pdata->irq_enable) + sensor->ops->ctrl_data |= KXTJ3_INT_ENABLE; + result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data); + if(result) + { + printk("%s:line=%d,error\n",__func__,__LINE__); + return result; + } + return result; +} + +static short sensor_convert_data(struct i2c_client *client, char high_byte, char low_byte) +{ + short result; + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + //int precision = sensor->ops->precision; + switch (sensor->devid) { + case KXTJ3_DEVID: + result = (((short)high_byte << 8) | ((short)low_byte)) >> 4; + result *= KXTJ3_GRAVITY_STEP; + break; + + default: + printk(KERN_ERR "%s: devid wasn't set correctly\n",__func__); + return -EFAULT; + } + + return result; +} + +static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + if (sensor->status_cur == SENSOR_ON) { + /* Report acceleration sensor information */ + input_report_abs(sensor->input_dev, ABS_X, axis->x); + input_report_abs(sensor->input_dev, ABS_Y, axis->y); + input_report_abs(sensor->input_dev, ABS_Z, axis->z); + input_sync(sensor->input_dev); + } + + return 0; +} + +#define GSENSOR_MIN 10 +static int sensor_report_value(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata = sensor->pdata; + int ret = 0; + short x, y, z; + struct sensor_axis axis; + char buffer[6] = {0}; + char value = 0; + + if(sensor->ops->read_len < 6) //sensor->ops->read_len = 6 + { + printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len); + return -1; + } + + memset(buffer, 0, 6); + + /* 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); + + //this gsensor need 6 bytes buffer + x = sensor_convert_data(sensor->client, buffer[1], buffer[0]); //buffer[1]:high bit + y = sensor_convert_data(sensor->client, buffer[3], buffer[2]); + z = sensor_convert_data(sensor->client, buffer[5], buffer[4]); + + axis.x = (pdata->orientation[0])*x + (pdata->orientation[1])*y + (pdata->orientation[2])*z; + axis.y = (pdata->orientation[3])*x + (pdata->orientation[4])*y + (pdata->orientation[5])*z; + axis.z = (pdata->orientation[6])*x + (pdata->orientation[7])*y + (pdata->orientation[8])*z; + + DBG( "%s: axis = %d %d %d \n", __func__, axis.x, axis.y, axis.z); + + gsensor_report_value(client, &axis); + + mutex_lock(&sensor->data_mutex); + sensor->axis = axis; + mutex_unlock(&sensor->data_mutex); + + 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); + } + return ret; +} + +struct sensor_operate gsensor_kxtj3_ops = { + .name = "kxtj3", + .type = SENSOR_TYPE_ACCEL, + .id_i2c = ACCEL_ID_KXTJ3, + .read_reg = KXTJ3_XOUT_L, + .read_len = 6, + .id_reg = KXTJ3_WHO_AM_I, + .id_data = KXTJ3_DEVID, + .precision = KXTJ3_PRECISION, + .ctrl_reg = KXTJ3_CTRL_REG1, + .int_status_reg = KXTJ3_INT_REL, + .range = {-32768, 32768}, + .trig = IRQF_TRIGGER_LOW | IRQF_ONESHOT, + .active = sensor_active, + .init = sensor_init, + .report = sensor_report_value, +}; + +/****************operate according to sensor chip:end************/ + +//function name should not be changed +static struct sensor_operate *gsensor_get_ops(void) +{ + return &gsensor_kxtj3_ops; +} + +static int __init gsensor_kxtj3_init(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int result = 0; + int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops); + return result; +} + +static void __exit gsensor_kxtj3_exit(void) +{ + struct sensor_operate *ops = gsensor_get_ops(); + int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops); +} + +module_init(gsensor_kxtj3_init); +module_exit(gsensor_kxtj3_exit); + diff --git a/drivers/input/sensors/sensor-dev.c b/drivers/input/sensors/sensor-dev.c new file mode 100755 index 0000000..5c351ef --- /dev/null +++ b/drivers/input/sensors/sensor-dev.c @@ -0,0 +1,1852 @@ +/* drivers/input/sensors/sensor-dev.c - handle all gsensor in this file + * + * Copyright (C) 2019 Khadas. + * Author: waylon + * + * 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 +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#ifdef CONFIG_COMPAT +#include +#endif + +#define SENSOR_CALIBRATION_LEN 64 +struct sensor_calibration_data { + s32 accel_offset[3]; + s32 gyro_offset[3]; + u8 is_accel_calibrated; + u8 is_gyro_calibrated; +}; + +static struct sensor_private_data *g_sensor[SENSOR_NUM_TYPES]; +static struct sensor_operate *sensor_ops[SENSOR_NUM_ID]; +static int sensor_probe_times[SENSOR_NUM_ID]; +static struct class *sensor_class; +static struct sensor_calibration_data sensor_cali_data; + +static int sensor_calibration_data_read(struct sensor_calibration_data *calibration_data) +{ +#if 0 + int ret; + u8 data[SENSOR_CALIBRATION_LEN] = {0}; + struct sensor_calibration_data *cdata = (struct sensor_calibration_data *)data; + + ret = rk_vendor_read(SENSOR_CALIBRATION_ID, (void *)data, SENSOR_CALIBRATION_LEN); + if (ret < 0) { + printk(KERN_ERR "%s failed\n", __func__); + return ret; + } + if (cdata->is_accel_calibrated == 1) { + calibration_data->accel_offset[0] = cdata->accel_offset[0]; + calibration_data->accel_offset[1] = cdata->accel_offset[1]; + calibration_data->accel_offset[2] = cdata->accel_offset[2]; + calibration_data->is_accel_calibrated = 1; + } + if (cdata->is_gyro_calibrated == 1) { + calibration_data->gyro_offset[0] = cdata->gyro_offset[0]; + calibration_data->gyro_offset[1] = cdata->gyro_offset[1]; + calibration_data->gyro_offset[2] = cdata->gyro_offset[2]; + calibration_data->is_gyro_calibrated = 1; + } +#endif + + return 0; +} + +static ssize_t accel_calibration_show(struct class *class, + struct class_attribute *attr, char *buf) +{ +#if 0 + int ret; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + + if (sensor == NULL) + return sprintf(buf, "no accel sensor find\n"); + + if (sensor_cali_data.is_accel_calibrated == 1) + return sprintf(buf, "accel calibration: %d, %d, %d\n", sensor_cali_data.accel_offset[0], + sensor_cali_data.accel_offset[1], sensor_cali_data.accel_offset[2]); + + ret = sensor_calibration_data_read(&sensor_cali_data); + if (ret) { + dev_err(&sensor->client->dev, "read accel sensor calibration data failed\n"); + return sprintf(buf, "read error\n"); + } + + if (sensor_cali_data.is_accel_calibrated == 1) + return sprintf(buf, "accel calibration: %d, %d, %d\n", sensor_cali_data.accel_offset[0], + sensor_cali_data.accel_offset[1], sensor_cali_data.accel_offset[2]); +#endif + return sprintf(buf, "read error\n"); +} + +#define ACCEL_CAPTURE_TIMES 20 +#define ACCEL_SENSITIVE 16384 +/* +-1 * 16384 / 9.8 */ +#define ACCEL_OFFSET_MAX 1600 + +static ssize_t accel_calibration_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ +#if 0 + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + int val, ret; + int pre_status; + + if (sensor == NULL) + return -1; + + ret = kstrtoint(buf, 10, &val); + if (ret) { + dev_err(&sensor->client->dev, "%s: kstrtoint error return %d\n", __func__, ret); + return -1; + } + if (val != 1) { + dev_err(&sensor->client->dev, "%s: error value\n", __func__); + return -1; + } + atomic_set(&sensor->is_factory, 1); + + pre_status = sensor->status_cur; + if (pre_status == SENSOR_OFF) { + mutex_lock(&sensor->operation_mutex); + sensor->ops->active(sensor->client, SENSOR_ON, sensor->pdata->poll_delay_ms); + mutex_unlock(&sensor->operation_mutex); + } else { + sensor->stop_work = 1; + if (sensor->pdata->irq_enable) + disable_irq_nosync(sensor->client->irq); + else + cancel_delayed_work_sync(&sensor->delaywork); + } + + ret = accel_do_calibration(sensor); + if (ret < 0) { + dev_err(&sensor->client->dev, "accel do calibration failed\n"); + goto OUT; + } + ret = sensor_calibration_data_write(&sensor_cali_data); + if (ret) + dev_err(&sensor->client->dev, "write accel sensor calibration data failed\n"); + +OUT: + if (pre_status == SENSOR_ON) { + sensor->stop_work = 0; + if (sensor->pdata->irq_enable) + enable_irq(sensor->client->irq); + else + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } else { + mutex_lock(&sensor->operation_mutex); + sensor->ops->active(sensor->client, SENSOR_OFF, sensor->pdata->poll_delay_ms); + mutex_unlock(&sensor->operation_mutex); + } + + atomic_set(&sensor->is_factory, 0); + wake_up(&sensor->is_factory_ok); + + return ret ? ret : count; +#endif + return count; +} + +static CLASS_ATTR(accel_calibration, 0664, accel_calibration_show, accel_calibration_store); + +static ssize_t gyro_calibration_show(struct class *class, + struct class_attribute *attr, char *buf) +{ +#if 0 + int ret; + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_GYROSCOPE]; + + if (sensor == NULL) + return sprintf(buf, "no gyro sensor find\n"); + + if (sensor_cali_data.is_gyro_calibrated == 1) + return sprintf(buf, "gyro calibration: %d, %d, %d\n", sensor_cali_data.gyro_offset[0], + sensor_cali_data.gyro_offset[1], sensor_cali_data.gyro_offset[2]); + + ret = sensor_calibration_data_read(&sensor_cali_data); + if (ret) { + dev_err(&sensor->client->dev, "read gyro sensor calibration data failed\n"); + return sprintf(buf, "read error\n"); + } + + if (sensor_cali_data.is_gyro_calibrated == 1) + return sprintf(buf, "gyro calibration: %d, %d, %d\n", sensor_cali_data.gyro_offset[0], + sensor_cali_data.gyro_offset[1], sensor_cali_data.gyro_offset[2]); + +#endif + return sprintf(buf, "read error\n"); +} + +#define GYRO_CAPTURE_TIMES 20 + +static ssize_t gyro_calibration_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ +#if 0 + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_GYROSCOPE]; + int val, ret; + int pre_status; + + if (sensor == NULL) + return -1; + + ret = kstrtoint(buf, 10, &val); + if (ret) { + dev_err(&sensor->client->dev, "%s: kstrtoint error return %d\n", __func__, ret); + return -1; + } + if (val != 1) { + dev_err(&sensor->client->dev, "%s error value\n", __func__); + return -1; + } + atomic_set(&sensor->is_factory, 1); + + pre_status = sensor->status_cur; + if (pre_status == SENSOR_OFF) { + mutex_lock(&sensor->operation_mutex); + sensor->ops->active(sensor->client, SENSOR_ON, sensor->pdata->poll_delay_ms); + mutex_unlock(&sensor->operation_mutex); + } else { + sensor->stop_work = 1; + if (sensor->pdata->irq_enable) + disable_irq_nosync(sensor->client->irq); + else + cancel_delayed_work_sync(&sensor->delaywork); + } + + ret = gyro_do_calibration(sensor); + if (ret < 0) { + dev_err(&sensor->client->dev, "gyro do calibration failed\n"); + goto OUT; + } + + ret = sensor_calibration_data_write(&sensor_cali_data); + if (ret) + dev_err(&sensor->client->dev, "write gyro sensor calibration data failed\n"); + +OUT: + if (pre_status == SENSOR_ON) { + sensor->stop_work = 0; + if (sensor->pdata->irq_enable) + enable_irq(sensor->client->irq); + else + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } else { + mutex_lock(&sensor->operation_mutex); + sensor->ops->active(sensor->client, SENSOR_OFF, sensor->pdata->poll_delay_ms); + mutex_unlock(&sensor->operation_mutex); + } + + atomic_set(&sensor->is_factory, 0); + wake_up(&sensor->is_factory_ok); + + return ret ? ret : count; +#endif + return count; +} + +static CLASS_ATTR(gyro_calibration, 0664, gyro_calibration_show, gyro_calibration_store); + +static int sensor_class_init(void) +{ + int ret ; + + sensor_class = class_create(THIS_MODULE, "sensor_class"); + ret = class_create_file(sensor_class, &class_attr_accel_calibration); + if (ret) { + printk(KERN_ERR "%s:Fail to creat accel class file\n", __func__); + return ret; + } + + ret = class_create_file(sensor_class, &class_attr_gyro_calibration); + if (ret) { + printk(KERN_ERR "%s:Fail to creat gyro class file\n", __func__); + return ret; + } + return 0; +} + +static int sensor_get_id(struct i2c_client *client, int *value) +{ + struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + char temp = sensor->ops->id_reg; + int i = 0; + + if (sensor->ops->id_reg >= 0) { + for (i = 0; i < 3; i++) { + result = sensor_rx_data(client, &temp, 1); + *value = temp; + if (!result) + break; + } + + if (result) + return result; + + if (*value != sensor->ops->id_data) { + dev_err(&client->dev, "%s:id=0x%x is not 0x%x\n", __func__, *value, sensor->ops->id_data); + result = -1; + } + } + + return result; +} + +static int sensor_initial(struct i2c_client *client) +{ + struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + /* register setting according to chip datasheet */ + result = sensor->ops->init(client); + if (result < 0) { + dev_err(&client->dev, "%s:fail to init sensor\n", __func__); + return result; + } + + return result; +} + +static int sensor_chip_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_operate *ops = sensor_ops[(int)sensor->i2c_id->driver_data]; + int result = 0; + + if (ops) { + sensor->ops = ops; + } else { + dev_err(&client->dev, "%s:ops is null,sensor name is %s\n", __func__, sensor->i2c_id->name); + result = -1; + goto error; + } + + if ((sensor->type != ops->type) || ((int)sensor->i2c_id->driver_data != ops->id_i2c)) { + dev_err(&client->dev, "%s:type or id is different:type=%d,%d,id=%d,%d\n", __func__, sensor->type, ops->type, (int)sensor->i2c_id->driver_data, ops->id_i2c); + result = -1; + goto error; + } + + if (!ops->init || !ops->active || !ops->report) { + dev_err(&client->dev, "%s:error:some function is needed\n", __func__); + result = -1; + goto error; + } + + result = sensor_get_id(sensor->client, &sensor->devid); + if (result < 0) { + dev_err(&client->dev, "%s:fail to read %s devid:0x%x\n", __func__, sensor->i2c_id->name, sensor->devid); + result = -2; + goto error; + } + + dev_info(&client->dev, "%s:%s:devid=0x%x,ops=0x%p\n", __func__, sensor->i2c_id->name, sensor->devid, sensor->ops); + + result = sensor_initial(sensor->client); + if (result < 0) { + dev_err(&client->dev, "%s:fail to init sensor\n", __func__); + result = -2; + goto error; + } + return 0; + +error: + return result; +} + +static int sensor_reset_rate(struct i2c_client *client, int rate) +{ + struct sensor_private_data *sensor = (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + + if (rate < 5) + rate = 5; + else if (rate > 200) + rate = 200; + + dev_info(&client->dev, "set sensor poll time to %dms\n", rate); + + /* work queue is always slow, we need more quickly to match hal rate */ + if (sensor->pdata->poll_delay_ms == (rate - 2)) + return 0; + + sensor->pdata->poll_delay_ms = rate - 2; + + if (sensor->status_cur == SENSOR_ON) { + if (!sensor->pdata->irq_enable) { + sensor->stop_work = 1; + cancel_delayed_work_sync(&sensor->delaywork); + } + result = sensor->ops->active(client, SENSOR_OFF, rate); + result = sensor->ops->active(client, SENSOR_ON, rate); + if (!sensor->pdata->irq_enable) { + sensor->stop_work = 0; + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + } + } + + return result; +} + +static void sensor_delaywork_func(struct work_struct *work) +{ + struct delayed_work *delaywork = container_of(work, struct delayed_work, work); + struct sensor_private_data *sensor = container_of(delaywork, struct sensor_private_data, delaywork); + struct i2c_client *client = sensor->client; + int result; + + mutex_lock(&sensor->sensor_mutex); + result = sensor->ops->report(client); + if (result < 0) + dev_err(&client->dev, "%s: Get data failed\n", __func__); + mutex_unlock(&sensor->sensor_mutex); + + //if ((!sensor->pdata->irq_enable) && (sensor->stop_work == 0)) + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); +} + +/* + * This is a threaded IRQ handler so can access I2C/SPI. Since all + * interrupts are clear on read the IRQ line will be reasserted and + * the physical IRQ will be handled again if another interrupt is + * asserted while we run - in the normal course of events this is a + * rare occurrence so we save I2C/SPI reads. We're also assuming that + * it's rare to get lots of interrupts firing simultaneously so try to + * minimise I/O. + */ +static irqreturn_t sensor_interrupt(int irq, void *dev_id) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *)dev_id; + struct i2c_client *client = sensor->client; + + mutex_lock(&sensor->sensor_mutex); + if (sensor->ops->report(client) < 0) + dev_err(&client->dev, "%s: Get data failed\n", __func__); + mutex_unlock(&sensor->sensor_mutex); + + return IRQ_HANDLED; +} + +static int sensor_irq_init(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + int result = 0; + int irq; + + if ((sensor->pdata->irq_enable) && (sensor->pdata->irq_flags != SENSOR_UNKNOW_DATA)) { + if (sensor->pdata->poll_delay_ms <= 0) + sensor->pdata->poll_delay_ms = 30; + result = gpio_request(client->irq, sensor->i2c_id->name); + if (result) + dev_err(&client->dev, "%s:fail to request gpio :%d\n", __func__, client->irq); + + irq = gpio_to_irq(client->irq); + result = devm_request_threaded_irq(&client->dev, irq, NULL, sensor_interrupt, sensor->pdata->irq_flags | IRQF_ONESHOT, sensor->ops->name, sensor); + if (result) { + dev_err(&client->dev, "%s:fail to request irq = %d, ret = 0x%x\n", __func__, irq, result); + goto error; + } + + client->irq = irq; + //disable_irq_nosync(client->irq); + sensor->ops->active(client, 1, sensor->pdata->poll_delay_ms); + + dev_info(&client->dev, "%s:use irq=%d\n", __func__, irq); + } else if (!sensor->pdata->irq_enable) { + INIT_DELAYED_WORK(&sensor->delaywork, sensor_delaywork_func); + sensor->stop_work = 1; + if (sensor->pdata->poll_delay_ms <= 0) + sensor->pdata->poll_delay_ms = 30; + + sensor->ops->active(client, 1, sensor->pdata->poll_delay_ms); + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + + dev_info(&client->dev, "%s:use polling,delay=%d ms\n", __func__, sensor->pdata->poll_delay_ms); + } + +error: + return result; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void sensor_suspend(struct early_suspend *h) +{ + struct sensor_private_data *sensor = + container_of(h, struct sensor_private_data, early_suspend); + + if (sensor->ops->suspend) + sensor->ops->suspend(sensor->client); +} + +static void sensor_resume(struct early_suspend *h) +{ + struct sensor_private_data *sensor = + container_of(h, struct sensor_private_data, early_suspend); + + if (sensor->ops->resume) + sensor->ops->resume(sensor->client); +} +#endif + +#ifdef CONFIG_PM +static int __maybe_unused sensor_of_suspend(struct device *dev) +{ + struct sensor_private_data *sensor = dev_get_drvdata(dev); + + if (sensor->ops->suspend) + sensor->ops->suspend(sensor->client); + + return 0; +} + +static int __maybe_unused sensor_of_resume(struct device *dev) +{ + struct sensor_private_data *sensor = dev_get_drvdata(dev); + + if (sensor->ops->resume) + sensor->ops->resume(sensor->client); + if (sensor->pdata->power_off_in_suspend) + sensor_initial(sensor->client); + + return 0; +} + +static const struct dev_pm_ops sensor_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sensor_of_suspend, sensor_of_resume) +}; + +#define SENSOR_PM_OPS (&sensor_pm_ops) +#else +#define SENSOR_PM_OPS NULL +#endif + +static int angle_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int angle_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static int sensor_enable(struct sensor_private_data *sensor, int enable) +{ + int result = 0; + struct i2c_client *client = sensor->client; + + if (enable == SENSOR_ON) { + result = sensor->ops->active(client, 1, sensor->pdata->poll_delay_ms); + if (result < 0) { + dev_err(&client->dev, "%s:fail to active sensor,ret=%d\n", __func__, result); + return result; + } + sensor->status_cur = SENSOR_ON; + sensor->stop_work = 0; + if (sensor->pdata->irq_enable) + enable_irq(client->irq); + else + schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); + dev_info(&client->dev, "sensor on: starting poll sensor data %dms\n", sensor->pdata->poll_delay_ms); + } else { + sensor->stop_work = 1; + if (sensor->pdata->irq_enable) + disable_irq_nosync(client->irq); + else + cancel_delayed_work_sync(&sensor->delaywork); + result = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms); + if (result < 0) { + dev_err(&client->dev, "%s:fail to disable sensor,ret=%d\n", __func__, result); + return result; + } + sensor->status_cur = SENSOR_OFF; + } + + return result; +} + +/* ioctl - I/O control */ +static long angle_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ANGLE]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; + struct sensor_axis axis = {0}; + short rate; + int result = 0; + + switch (cmd) { + case GSENSOR_IOCTL_APP_SET_RATE: + if (copy_from_user(&rate, argp, sizeof(rate))) { + result = -EFAULT; + goto error; + } + break; + default: + break; + } + + switch (cmd) { + case GSENSOR_IOCTL_START: + mutex_lock(&sensor->operation_mutex); + if (++sensor->start_count == 1) { + if (sensor->status_cur == SENSOR_OFF) { + sensor_enable(sensor, SENSOR_ON); + } + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_CLOSE: + mutex_lock(&sensor->operation_mutex); + if (--sensor->start_count == 0) { + if (sensor->status_cur == SENSOR_ON) { + sensor_enable(sensor, SENSOR_OFF); + } + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_APP_SET_RATE: + mutex_lock(&sensor->operation_mutex); + result = sensor_reset_rate(client, rate); + if (result < 0) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_GETDATA: + mutex_lock(&sensor->data_mutex); + memcpy(&axis, &sensor->axis, sizeof(sensor->axis)); + mutex_unlock(&sensor->data_mutex); + break; + + default: + result = -ENOTTY; + + goto error; + } + + switch (cmd) { + case GSENSOR_IOCTL_GETDATA: + if (copy_to_user(argp, &axis, sizeof(axis))) { + dev_err(&client->dev, "failed to copy sense data to user space.\n"); + result = -EFAULT; + goto error; + } + break; + default: + break; + } + +error: + return result; +} + + +static int gsensor_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int gsensor_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/* ioctl - I/O control */ +static long gsensor_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_ACCEL]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; + struct sensor_axis axis = {0}; + short rate; + int result = 0; + + wait_event_interruptible(sensor->is_factory_ok, (atomic_read(&sensor->is_factory) == 0)); + + switch (cmd) { + case GSENSOR_IOCTL_APP_SET_RATE: + if (copy_from_user(&rate, argp, sizeof(rate))) { + result = -EFAULT; + goto error; + } + break; + default: + break; + } + + switch (cmd) { + case GSENSOR_IOCTL_START: + mutex_lock(&sensor->operation_mutex); + if (++sensor->start_count == 1) { + if (sensor->status_cur == SENSOR_OFF) { + sensor_enable(sensor, SENSOR_ON); + } + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_CLOSE: + mutex_lock(&sensor->operation_mutex); + if (--sensor->start_count == 0) { + if (sensor->status_cur == SENSOR_ON) { + sensor_enable(sensor, SENSOR_OFF); + } + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_APP_SET_RATE: + mutex_lock(&sensor->operation_mutex); + result = sensor_reset_rate(client, rate); + if (result < 0) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + mutex_unlock(&sensor->operation_mutex); + break; + + case GSENSOR_IOCTL_GETDATA: + mutex_lock(&sensor->data_mutex); + memcpy(&axis, &sensor->axis, sizeof(sensor->axis)); + mutex_unlock(&sensor->data_mutex); + break; + + case GSENSOR_IOCTL_GET_CALIBRATION: + if (sensor_cali_data.is_accel_calibrated != 1) { + if (sensor_calibration_data_read(&sensor_cali_data)) { + dev_err(&client->dev, "failed to read accel offset data from storage\n"); + result = -EFAULT; + goto error; + } + } + if (sensor_cali_data.is_accel_calibrated == 1) { + if (copy_to_user(argp, sensor_cali_data.accel_offset, sizeof(sensor_cali_data.accel_offset))) { + dev_err(&client->dev, "failed to copy accel offset data to user\n"); + result = -EFAULT; + goto error; + } + } + break; + + default: + result = -ENOTTY; + goto error; + } + + switch (cmd) { + case GSENSOR_IOCTL_GETDATA: + if (copy_to_user(argp, &axis, sizeof(axis))) { + dev_err(&client->dev, "failed to copy sense data to user space.\n"); + result = -EFAULT; + goto error; + } + break; + default: + break; + } + +error: + return result; +} + +static int compass_dev_open(struct inode *inode, struct file *file) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + int result = 0; + 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); + } + + return result; +} + +static int compass_dev_release(struct inode *inode, struct file *file) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_COMPASS]; + int result = 0; + 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); + } + + return result; +} + +#ifdef CONFIG_COMPAT +/* ioctl - I/O control */ +static long compass_dev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *arg64 = compat_ptr(arg); + int result = 0; + + if (!file->f_op || !file->f_op->unlocked_ioctl) { + printk(KERN_ERR "file->f_op or file->f_op->unlocked_ioctl is null\n"); + return -ENOTTY; + } + + switch (cmd) { + case COMPAT_ECS_IOCTL_APP_SET_MFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_SET_MFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_GET_MFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_GET_MFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_SET_AFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_SET_AFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_GET_AFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_GET_AFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_SET_MVFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_SET_MVFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_GET_MVFLAG: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_GET_MVFLAG, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_SET_DELAY: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_SET_DELAY, (unsigned long)arg64); + break; + case COMPAT_ECS_IOCTL_APP_GET_DELAY: + if (file->f_op->unlocked_ioctl) + result = file->f_op->unlocked_ioctl(file, ECS_IOCTL_APP_GET_DELAY, (unsigned long)arg64); + break; + default: + break; + } + + return result; +} +#endif + +/* 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]; + 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(&sensor->flags.m_flag, flag); + break; + case ECS_IOCTL_APP_GET_MFLAG: + flag = atomic_read(&sensor->flags.m_flag); + break; + case ECS_IOCTL_APP_SET_AFLAG: + atomic_set(&sensor->flags.a_flag, flag); + break; + case ECS_IOCTL_APP_GET_AFLAG: + flag = atomic_read(&sensor->flags.a_flag); + break; + case ECS_IOCTL_APP_SET_MVFLAG: + atomic_set(&sensor->flags.mv_flag, flag); + break; + case ECS_IOCTL_APP_GET_MVFLAG: + flag = atomic_read(&sensor->flags.mv_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; +} + + +static int light_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int light_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + +#ifdef CONFIG_COMPAT +static long light_dev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + void __user *arg64 = compat_ptr(arg); + + if (!file->f_op || !file->f_op->unlocked_ioctl) { + printk(KERN_ERR "[DEBUG] file->f_op or file->f_op->unlocked_ioctl is null\n"); + return -ENOTTY; + } + + switch (cmd) { + case COMPAT_LIGHTSENSOR_IOCTL_GET_ENABLED: + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, LIGHTSENSOR_IOCTL_GET_ENABLED, (unsigned long)arg64); + break; + case COMPAT_LIGHTSENSOR_IOCTL_ENABLE: + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, LIGHTSENSOR_IOCTL_ENABLE, (unsigned long)arg64); + break; + case COMPAT_LIGHTSENSOR_IOCTL_SET_RATE: + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, LIGHTSENSOR_IOCTL_SET_RATE, (unsigned long)arg64); + break; + default: + break; + } + + return ret; +} +#endif + +/* ioctl - I/O control */ +static long light_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_LIGHT]; + struct i2c_client *client = sensor->client; + void __user *argp = (void __user *)arg; + int result = 0; + short rate; + + switch (cmd) { + case LIGHTSENSOR_IOCTL_SET_RATE: + if (copy_from_user(&rate, argp, sizeof(rate))) { + dev_err(&client->dev, "%s:failed to copy light sensor rate from user space.\n", __func__); + return -EFAULT; + } + mutex_lock(&sensor->operation_mutex); + result = sensor_reset_rate(client, rate); + if (result < 0) { + mutex_unlock(&sensor->operation_mutex); + goto error; + } + mutex_unlock(&sensor->operation_mutex); + break; + case LIGHTSENSOR_IOCTL_GET_ENABLED: + result = sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) { + dev_err(&client->dev, "%s:failed to copy light sensor status to user space.\n", __func__); + return -EFAULT; + } + break; + case LIGHTSENSOR_IOCTL_ENABLE: + if (copy_from_user(&result, argp, sizeof(result))) { + dev_err(&client->dev, "%s:failed to copy light sensor status from user space.\n", __func__); + return -EFAULT; + } + + mutex_lock(&sensor->operation_mutex); + if (result) { + if (sensor->status_cur == SENSOR_OFF) + sensor_enable(sensor, SENSOR_ON); + } else { + if (sensor->status_cur == SENSOR_ON) + sensor_enable(sensor, SENSOR_OFF); + } + mutex_unlock(&sensor->operation_mutex); + break; + + default: + break; + } + +error: + return result; +} + +static int proximity_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int proximity_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + +#ifdef CONFIG_COMPAT +static long proximity_dev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + void __user *arg64 = compat_ptr(arg); + + if (!file->f_op || !file->f_op->unlocked_ioctl) { + printk(KERN_ERR "file->f_op or file->f_op->unlocked_ioctl is null\n"); + return -ENOTTY; + } + + switch (cmd) { + case COMPAT_PSENSOR_IOCTL_GET_ENABLED: + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, PSENSOR_IOCTL_GET_ENABLED, (unsigned long)arg64); + break; + case COMPAT_PSENSOR_IOCTL_ENABLE: + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, PSENSOR_IOCTL_ENABLE, (unsigned long)arg64); + break; + default: + break; + } + + return ret; +} +#endif + +/* ioctl - I/O control */ +static long proximity_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_PROXIMITY]; + void __user *argp = (void __user *)arg; + int result = 0; + + switch (cmd) { + case PSENSOR_IOCTL_GET_ENABLED: + result = sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy psensor status to user space.\n", __func__); + return -EFAULT; + } + break; + case PSENSOR_IOCTL_ENABLE: + if (copy_from_user(&result, argp, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy psensor status from user space.\n", __func__); + return -EFAULT; + } + mutex_lock(&sensor->operation_mutex); + if (result) { + if (sensor->status_cur == SENSOR_OFF) + sensor_enable(sensor, SENSOR_ON); + } else { + if (sensor->status_cur == SENSOR_ON) + sensor_enable(sensor, SENSOR_OFF); + } + mutex_unlock(&sensor->operation_mutex); + break; + + default: + break; + } + + return result; +} + +static int temperature_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int temperature_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/* ioctl - I/O control */ +static long temperature_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_TEMPERATURE]; + void __user *argp = (void __user *)arg; + int result = 0; + + switch (cmd) { + case TEMPERATURE_IOCTL_GET_ENABLED: + result = sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy temperature sensor status to user space.\n", __func__); + return -EFAULT; + } + break; + case TEMPERATURE_IOCTL_ENABLE: + if (copy_from_user(&result, argp, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy temperature sensor status from user space.\n", __func__); + return -EFAULT; + } + mutex_lock(&sensor->operation_mutex); + if (result) { + if (sensor->status_cur == SENSOR_OFF) + sensor_enable(sensor, SENSOR_ON); + } else { + if (sensor->status_cur == SENSOR_ON) + sensor_enable(sensor, SENSOR_OFF); + } + mutex_unlock(&sensor->operation_mutex); + break; + + default: + break; + } + + return result; +} + + +static int pressure_dev_open(struct inode *inode, struct file *file) +{ + return 0; +} + + +static int pressure_dev_release(struct inode *inode, struct file *file) +{ + return 0; +} + + +/* ioctl - I/O control */ +static long pressure_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct sensor_private_data *sensor = g_sensor[SENSOR_TYPE_PRESSURE]; + void __user *argp = (void __user *)arg; + int result = 0; + + switch (cmd) { + case PRESSURE_IOCTL_GET_ENABLED: + result = sensor->status_cur; + if (copy_to_user(argp, &result, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy pressure sensor status to user space.\n", __func__); + return -EFAULT; + } + break; + case PRESSURE_IOCTL_ENABLE: + if (copy_from_user(&result, argp, sizeof(result))) { + dev_err(&sensor->client->dev, "%s:failed to copy pressure sensor status from user space.\n", __func__); + return -EFAULT; + } + mutex_lock(&sensor->operation_mutex); + if (result) { + if (sensor->status_cur == SENSOR_OFF) + sensor_enable(sensor, SENSOR_ON); + } else { + if (sensor->status_cur == SENSOR_ON) + sensor_enable(sensor, SENSOR_OFF); + } + mutex_unlock(&sensor->operation_mutex); + break; + + default: + break; + } + + return result; +} + +static int sensor_misc_device_register(struct sensor_private_data *sensor, int type) +{ + int result = 0; + + switch (type) { + case SENSOR_TYPE_ANGLE: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = angle_dev_ioctl; + sensor->fops.open = angle_dev_open; + sensor->fops.release = angle_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "angle"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_ACCEL: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = gsensor_dev_ioctl; + #ifdef CONFIG_COMPAT + sensor->fops.compat_ioctl = gsensor_dev_ioctl; + #endif + sensor->fops.open = gsensor_dev_open; + sensor->fops.release = gsensor_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "accel"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_COMPASS: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = compass_dev_ioctl; + #ifdef CONFIG_COMPAT + sensor->fops.compat_ioctl = compass_dev_compat_ioctl; + #endif + sensor->fops.open = compass_dev_open; + sensor->fops.release = compass_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "compass"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_LIGHT: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = light_dev_ioctl; + #ifdef CONFIG_COMPAT + sensor->fops.compat_ioctl = light_dev_compat_ioctl; + #endif + sensor->fops.open = light_dev_open; + sensor->fops.release = light_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "lightsensor"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_PROXIMITY: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = proximity_dev_ioctl; + #ifdef CONFIG_COMPAT + sensor->fops.compat_ioctl = proximity_dev_compat_ioctl; + #endif + sensor->fops.open = proximity_dev_open; + sensor->fops.release = proximity_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "psensor"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_TEMPERATURE: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = temperature_dev_ioctl; + sensor->fops.open = temperature_dev_open; + sensor->fops.release = temperature_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "temperature"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + case SENSOR_TYPE_PRESSURE: + if (!sensor->ops->misc_dev) { + sensor->fops.owner = THIS_MODULE; + sensor->fops.unlocked_ioctl = pressure_dev_ioctl; + sensor->fops.open = pressure_dev_open; + sensor->fops.release = pressure_dev_release; + + sensor->miscdev.minor = MISC_DYNAMIC_MINOR; + sensor->miscdev.name = "pressure"; + sensor->miscdev.fops = &sensor->fops; + } else { + memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev)); + } + break; + + default: + dev_err(&sensor->client->dev, "%s:unknow sensor type=%d\n", __func__, type); + result = -1; + goto error; + } + + sensor->miscdev.parent = &sensor->client->dev; + result = misc_register(&sensor->miscdev); + if (result < 0) { + dev_err(&sensor->client->dev, + "fail to register misc device %s\n", sensor->miscdev.name); + goto error; + } + dev_info(&sensor->client->dev, "%s:miscdevice: %s\n", __func__, sensor->miscdev.name); + +error: + return result; +} + +int sensor_register_slave(int type, struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)) +{ + int result = 0; + struct sensor_operate *ops = get_sensor_ops(); + + if (ops->id_i2c >= SENSOR_NUM_ID) { + printk(KERN_ERR "%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c); + return -1; + } + sensor_ops[ops->id_i2c] = ops; + sensor_probe_times[ops->id_i2c] = 0; + + printk(KERN_INFO "%s:%s,id=%d\n", __func__, sensor_ops[ops->id_i2c]->name, ops->id_i2c); + + return result; +} + +int sensor_unregister_slave(int type, struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)) +{ + int result = 0; + struct sensor_operate *ops = get_sensor_ops(); + + if (ops->id_i2c >= SENSOR_NUM_ID) { + printk(KERN_ERR "%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c); + return -1; + } + printk(KERN_INFO "%s:%s,id=%d\n", __func__, sensor_ops[ops->id_i2c]->name, ops->id_i2c); + sensor_ops[ops->id_i2c] = NULL; + + return result; +} + +int sensor_probe(struct i2c_client *client, const struct i2c_device_id *devid) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + struct sensor_platform_data *pdata; + struct device_node *np = client->dev.of_node; + enum of_gpio_flags rst_flags, pwr_flags; + unsigned long irq_flags; + int result = 0; + int type = 0; + int reprobe_en = 0; + + dev_info(&client->adapter->dev, "%s: %s,%p\n", __func__, devid->name, client); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + if (!np) { + dev_err(&client->dev, "no device tree\n"); + return -EINVAL; + } + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + result = -ENOMEM; + goto out_no_free; + } + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) { + result = -ENOMEM; + goto out_no_free; + } + + of_property_read_u32(np, "type", &(pdata->type)); + + pdata->irq_pin = of_get_named_gpio_flags(np, "irq-gpio", 0, (enum of_gpio_flags *)&irq_flags); + pdata->reset_pin = of_get_named_gpio_flags(np, "reset-gpio", 0, &rst_flags); + pdata->power_pin = of_get_named_gpio_flags(np, "power-gpio", 0, &pwr_flags); + + of_property_read_u32(np, "irq_enable", &(pdata->irq_enable)); + of_property_read_u32(np, "poll_delay_ms", &(pdata->poll_delay_ms)); + + of_property_read_u32(np, "x_min", &(pdata->x_min)); + of_property_read_u32(np, "y_min", &(pdata->y_min)); + of_property_read_u32(np, "z_min", &(pdata->z_min)); + of_property_read_u32(np, "factory", &(pdata->factory)); + of_property_read_u32(np, "layout", &(pdata->layout)); + of_property_read_u32(np, "reprobe_en", &reprobe_en); + + of_property_read_u8(np, "address", &(pdata->address)); + of_get_property(np, "project_name", pdata->project_name); + + of_property_read_u32(np, "power-off-in-suspend", + &pdata->power_off_in_suspend); + + switch (pdata->layout) { + case 1: + pdata->orientation[0] = 1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = 1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + + case 2: + pdata->orientation[0] = 0; + pdata->orientation[1] = -1; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 1; + pdata->orientation[4] = 0; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + + case 3: + pdata->orientation[0] = -1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = -1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + + case 4: + pdata->orientation[0] = 0; + pdata->orientation[1] = 1; + pdata->orientation[2] = 0; + + pdata->orientation[3] = -1; + pdata->orientation[4] = 0; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + + case 5: + pdata->orientation[0] = 1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = -1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = -1; + break; + + case 6: + pdata->orientation[0] = 0; + pdata->orientation[1] = -1; + pdata->orientation[2] = 0; + + pdata->orientation[3] = -1; + pdata->orientation[4] = 0; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = -1; + break; + + case 7: + pdata->orientation[0] = -1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = 1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = -1; + break; + + case 8: + pdata->orientation[0] = 0; + pdata->orientation[1] = 1; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 1; + pdata->orientation[4] = 0; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = -1; + break; + case 9: + pdata->orientation[0] = 1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = -1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + default: + pdata->orientation[0] = 1; + pdata->orientation[1] = 0; + pdata->orientation[2] = 0; + + pdata->orientation[3] = 0; + pdata->orientation[4] = 1; + pdata->orientation[5] = 0; + + pdata->orientation[6] = 0; + pdata->orientation[7] = 0; + pdata->orientation[8] = 1; + break; + } + + client->irq = pdata->irq_pin; + type = pdata->type; + pdata->irq_flags = irq_flags; + //pdata->poll_delay_ms = 30; + + if ((type >= SENSOR_NUM_TYPES) || (type <= SENSOR_TYPE_NULL)) { + dev_err(&client->adapter->dev, "sensor type is error %d\n", type); + result = -EFAULT; + goto out_no_free; + } + + i2c_set_clientdata(client, sensor); + sensor->client = client; + sensor->pdata = pdata; + sensor->type = type; + sensor->i2c_id = (struct i2c_device_id *)devid; + + memset(&(sensor->axis), 0, sizeof(struct sensor_axis)); + mutex_init(&sensor->data_mutex); + mutex_init(&sensor->operation_mutex); + mutex_init(&sensor->sensor_mutex); + mutex_init(&sensor->i2c_mutex); + + atomic_set(&sensor->is_factory, 0); + init_waitqueue_head(&sensor->is_factory_ok); + + /* 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); + atomic_set(&sensor->flags.debug_flag, 1); + init_waitqueue_head(&sensor->flags.open_wq); + sensor->flags.delay = 100; + + sensor->status_cur = SENSOR_OFF; + sensor->axis.x = 0; + sensor->axis.y = 0; + sensor->axis.z = 0; + + result = sensor_chip_init(sensor->client); + if (result < 0) { + if (reprobe_en && (result == -2)) { + sensor_probe_times[sensor->ops->id_i2c]++; + if (sensor_probe_times[sensor->ops->id_i2c] < 3) + result = -EPROBE_DEFER; + } + goto out_free_memory; + } + + sensor->input_dev = devm_input_allocate_device(&client->dev); + if (!sensor->input_dev) { + result = -ENOMEM; + dev_err(&client->dev, + "Failed to allocate input device\n"); + goto out_free_memory; + } + + switch (type) { + case SENSOR_TYPE_ANGLE: + sensor->input_dev->name = "angle"; + set_bit(EV_ABS, sensor->input_dev->evbit); + /* x-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_X, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* y-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Y, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* z-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Z, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + + case SENSOR_TYPE_ACCEL: + sensor->input_dev->name = "gsensor"; + set_bit(EV_ABS, sensor->input_dev->evbit); + /* x-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_X, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* y-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Y, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* z-axis acceleration */ + input_set_abs_params(sensor->input_dev, ABS_Z, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_COMPASS: + sensor->input_dev->name = "compass"; + /* Setup input device */ + set_bit(EV_ABS, sensor->input_dev->evbit); + /* yaw (0, 360) */ + input_set_abs_params(sensor->input_dev, ABS_RX, 0, 23040, 0, 0); + /* pitch (-180, 180) */ + input_set_abs_params(sensor->input_dev, ABS_RY, -11520, 11520, 0, 0); + /* roll (-90, 90) */ + input_set_abs_params(sensor->input_dev, ABS_RZ, -5760, 5760, 0, 0); + /* x-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_X, -5760, 5760, 0, 0); + /* y-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_Y, -5760, 5760, 0, 0); + /* z-axis acceleration (720 x 8G) */ + input_set_abs_params(sensor->input_dev, ABS_Z, -5760, 5760, 0, 0); + /* status of magnetic sensor */ + input_set_abs_params(sensor->input_dev, ABS_RUDDER, -32768, 3, 0, 0); + /* status of acceleration sensor */ + input_set_abs_params(sensor->input_dev, ABS_WHEEL, -32768, 3, 0, 0); + /* x-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_HAT0X, -20480, 20479, 0, 0); + /* y-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_HAT0Y, -20480, 20479, 0, 0); + /* z-axis of raw magnetic vector (-4096, 4095) */ + input_set_abs_params(sensor->input_dev, ABS_BRAKE, -20480, 20479, 0, 0); + break; + case SENSOR_TYPE_GYROSCOPE: + sensor->input_dev->name = "gyro"; + /* x-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RX); + input_set_abs_params(sensor->input_dev, ABS_RX, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* y-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RY); + input_set_abs_params(sensor->input_dev, ABS_RY, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + /* z-axis acceleration */ + input_set_capability(sensor->input_dev, EV_REL, REL_RZ); + input_set_abs_params(sensor->input_dev, ABS_RZ, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_LIGHT: + sensor->input_dev->name = "lightsensor-level"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_MISC, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + input_set_abs_params(sensor->input_dev, ABS_TOOL_WIDTH, sensor->ops->brightness[0], sensor->ops->brightness[1], 0, 0); + break; + case SENSOR_TYPE_PROXIMITY: + sensor->input_dev->name = "proximity"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_DISTANCE, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_TEMPERATURE: + sensor->input_dev->name = "temperature"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_THROTTLE, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + case SENSOR_TYPE_PRESSURE: + sensor->input_dev->name = "pressure"; + set_bit(EV_ABS, sensor->input_dev->evbit); + input_set_abs_params(sensor->input_dev, ABS_PRESSURE, sensor->ops->range[0], sensor->ops->range[1], 0, 0); + break; + default: + dev_err(&client->dev, "%s:unknow sensor type=%d\n", __func__, type); + break; + } + sensor->input_dev->dev.parent = &client->dev; + + result = input_register_device(sensor->input_dev); + if (result) { + dev_err(&client->dev, + "Unable to register input device %s\n", sensor->input_dev->name); + goto out_input_register_device_failed; + } + + result = sensor_irq_init(sensor->client); + if (result) { + dev_err(&client->dev, + "fail to init sensor irq,ret=%d\n", result); + goto out_input_register_device_failed; + } + + sensor->miscdev.parent = &client->dev; + result = sensor_misc_device_register(sensor, type); + if (result) { + dev_err(&client->dev, + "fail to register misc device %s\n", sensor->miscdev.name); + goto out_misc_device_register_device_failed; + } + + g_sensor[type] = sensor; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if ((sensor->ops->suspend) && (sensor->ops->resume)) { + sensor->early_suspend.suspend = sensor_suspend; + sensor->early_suspend.resume = sensor_resume; + sensor->early_suspend.level = 0x02; + register_early_suspend(&sensor->early_suspend); + } +#endif + dev_info(&client->dev, "%s:initialized ok,sensor name:%s,type:%d,id=%d\n\n", __func__, sensor->ops->name, type, (int)sensor->i2c_id->driver_data); + + return result; + +out_misc_device_register_device_failed: +out_input_register_device_failed: +out_free_memory: +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n\n", __func__, result); + return result; +} + +static void sensor_shut_down(struct i2c_client *client) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + if ((sensor->ops->suspend) && (sensor->ops->resume)) + unregister_early_suspend(&sensor->early_suspend); +#endif +} + +static int sensor_remove(struct i2c_client *client) +{ + struct sensor_private_data *sensor = + (struct sensor_private_data *) i2c_get_clientdata(client); + + sensor->stop_work = 1; + cancel_delayed_work_sync(&sensor->delaywork); + misc_deregister(&sensor->miscdev); +#ifdef CONFIG_HAS_EARLYSUSPEND + if ((sensor->ops->suspend) && (sensor->ops->resume)) + unregister_early_suspend(&sensor->early_suspend); +#endif + + return 0; +} + +static const struct i2c_device_id sensor_id[] = { + /*gsensor*/ + {"kxtj3", ACCEL_ID_KXTJ3}, + {}, +}; + +static struct of_device_id sensor_dt_ids[] = { + /*gsensor*/ + { .compatible = "kxtj3" }, + { } +}; + +static struct i2c_driver sensor_driver = { + .probe = sensor_probe, + .remove = sensor_remove, + .shutdown = sensor_shut_down, + .id_table = sensor_id, + .driver = { + .name = "sensors", + .of_match_table = of_match_ptr(sensor_dt_ids), + .pm = SENSOR_PM_OPS, + }, +}; + +static int __init sensor_init(void) +{ + sensor_class_init(); + return i2c_add_driver(&sensor_driver); +} + +static void __exit sensor_exit(void) +{ + i2c_del_driver(&sensor_driver); +} + +late_initcall(sensor_init); +module_exit(sensor_exit); + +MODULE_AUTHOR("Waylon waylon@khadas.com"); +MODULE_DESCRIPTION("User space character device interface for sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/sensors/sensor-i2c.c b/drivers/input/sensors/sensor-i2c.c new file mode 100755 index 0000000..0e418a5 --- /dev/null +++ b/drivers/input/sensors/sensor-i2c.c @@ -0,0 +1,241 @@ +/* drivers/input/sensors/sensor-i2c.c - sensor i2c handle + * + * Copyright (C) 2019 Khadas. + * Author: Waylon + * + * 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 +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#define SENSOR_I2C_RATE 200*1000 + + +static int sensor_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char const *data) +{ + struct i2c_msg msgs[1]; + int res; + + if (!data || !i2c_adap) { + printk("%s:line=%d,error\n",__func__,__LINE__); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = (unsigned char *)data; + msgs[0].len = len; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res == 1) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + +static int senosr_i2c_read(struct i2c_adapter *i2c_adap, + unsigned char address, unsigned char reg, + unsigned int len, unsigned char *data) +{ + struct i2c_msg msgs[2]; + int res; + + if (!data || !i2c_adap) { + printk("%s:line=%d,error\n",__func__,__LINE__); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = address; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = len; + + res = i2c_transfer(i2c_adap, msgs, 2); + if (res == 2) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + + +int sensor_rx_data(struct i2c_client *client, char *rxData, int length) +{ + int i = 0; + int ret = 0; + char reg = rxData[0]; + ret = senosr_i2c_read(client->adapter, client->addr, reg, length, rxData); + + DBG("addr=0x%x,len=%d,rxdata:",reg,length); + for(i=0; iadapter, client->addr, length, txData); + return ret; + +} +EXPORT_SYMBOL(sensor_tx_data); + +int sensor_write_reg(struct i2c_client *client, int addr, int value) +{ + char buffer[2]; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + buffer[0] = addr; + buffer[1] = value; + ret = sensor_tx_data(client, &buffer[0], 2); + mutex_unlock(&sensor->i2c_mutex); + return ret; +} +EXPORT_SYMBOL(sensor_write_reg); + +int sensor_read_reg(struct i2c_client *client, int addr) +{ + char tmp[1] = {0}; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + tmp[0] = addr; + ret = sensor_rx_data(client, tmp, 1); + mutex_unlock(&sensor->i2c_mutex); + + return tmp[0]; +} + +EXPORT_SYMBOL(sensor_read_reg); + +static int i2c_master_normal_recv(const struct i2c_client *client, char *buf, int count, int scl_rate) + { + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + int ret; + + msg.addr = client->addr; + msg.flags = client->flags | I2C_M_RD; + msg.len = count; + msg.buf = (char *)buf; + ret = i2c_transfer(adap, &msg, 1); + + return (ret == 1) ? count : ret; +} + +static int i2c_master_normal_send(const struct i2c_client *client, const char *buf, int count, int scl_rate) +{ + int ret; + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = count; + msg.buf = (char *)buf; + + ret = i2c_transfer(adap, &msg, 1); + return (ret == 1) ? count : ret; +} + +int sensor_tx_data_normal(struct i2c_client *client, char *buf, int num) +{ + int ret = 0; + ret = i2c_master_normal_send(client, buf, num, SENSOR_I2C_RATE); + + return (ret == num) ? 0 : ret; +} +EXPORT_SYMBOL(sensor_tx_data_normal); + + +int sensor_rx_data_normal(struct i2c_client *client, char *buf, int num) +{ + int ret = 0; + ret = i2c_master_normal_recv(client, buf, num, SENSOR_I2C_RATE); + + return (ret == num) ? 0 : ret; +} + +EXPORT_SYMBOL(sensor_rx_data_normal); + + +int sensor_write_reg_normal(struct i2c_client *client, char value) +{ + char buffer[2]; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + buffer[0] = value; + ret = sensor_tx_data_normal(client, &buffer[0], 1); + mutex_unlock(&sensor->i2c_mutex); + return ret; +} +EXPORT_SYMBOL(sensor_write_reg_normal); + +int sensor_read_reg_normal(struct i2c_client *client) +{ + char tmp[1] = {0}; + int ret = 0; + struct sensor_private_data* sensor = + (struct sensor_private_data *)i2c_get_clientdata(client); + + mutex_lock(&sensor->i2c_mutex); + ret = sensor_rx_data_normal(client, tmp, 1); + mutex_unlock(&sensor->i2c_mutex); + + return tmp[0]; +} + +EXPORT_SYMBOL(sensor_read_reg_normal); + diff --git a/include/linux/sensor-dev.h b/include/linux/sensor-dev.h new file mode 100755 index 0000000..81ef7b0 --- /dev/null +++ b/include/linux/sensor-dev.h @@ -0,0 +1,263 @@ +/* include/linux/sensor-dev.h - sensor header file + * + * 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 +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#define SENSOR_TYPE_NULL 0 +#define SENSOR_TYPE_ANGLE 1 +#define SENSOR_TYPE_ACCEL 2 +#define SENSOR_TYPE_COMPASS 3 +#define SENSOR_TYPE_GYROSCOPE 4 +#define SENSOR_TYPE_LIGHT 5 +#define SENSOR_TYPE_PROXIMITY 6 +#define SENSOR_TYPE_TEMPERATURE 7 +#define SENSOR_TYPE_PRESSURE 8 +#define SENSOR_TYPE_HALL 9 +#define SENSOR_NUM_TYPES 10 + +#define SENSOR_ON 1 +#define SENSOR_OFF 0 +#define SENSOR_UNKNOW_DATA -1 + +#define GPIO_HIGH 1 +#define GPIO_LOW 0 + +enum sensor_id { + ACCEL_ID_KXTJ3 = 0, + SENSOR_NUM_ID, +}; + +struct sensor_axis { + int x; + int y; + int z; +}; + +struct sensor_flag { + atomic_t a_flag; + atomic_t m_flag; + atomic_t mv_flag; + atomic_t open_flag; + atomic_t debug_flag; + long long delay; + wait_queue_head_t open_wq; +}; + + +struct sensor_operate { + char *name; + int type; + int id_i2c; + int range[2]; + int brightness[2]; + int read_reg; + int read_len; + int id_reg; + int id_data; + int precision; + int ctrl_reg; + int ctrl_data; + int int_ctrl_reg; + int int_status_reg; + int trig; + int (*active)(struct i2c_client *client, int enable, int rate); + int (*init)(struct i2c_client *client); + int (*report)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client); + int (*resume)(struct i2c_client *client); + struct miscdevice *misc_dev; +}; + +/* Platform data for the sensor */ +struct sensor_private_data { + int type; + struct i2c_client *client; + struct input_dev *input_dev; + int stop_work; + struct delayed_work delaywork; + struct sensor_axis axis; + char sensor_data[40]; + atomic_t is_factory; + wait_queue_head_t is_factory_ok; + struct mutex data_mutex; + struct mutex operation_mutex; + struct mutex sensor_mutex; + struct mutex i2c_mutex; + 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; + struct file_operations fops; + struct miscdevice miscdev; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +struct sensor_platform_data { + int type; + int irq; + int irq_pin; + int power_pin; + int reset_pin; + int standby_pin; + int irq_enable; + int poll_delay_ms; + int x_min; + int y_min; + int z_min; + int factory; + int layout; + unsigned char address; + unsigned long irq_flags; + signed char orientation[9]; + short m_layout[4][3][3]; + int *project_name; + int power_off_in_suspend; +}; + +struct gsensor_platform_data { + u16 model; + u16 swap_xy; + u16 swap_xyz; + signed char orientation[9]; + int (*get_pendown_state)(void); + int (*init_platform_hw)(void); + int (*gsensor_platform_sleep)(void); + int (*gsensor_platform_wakeup)(void); + void (*exit_platform_hw)(void); +}; + +struct akm8975_platform_data { + short m_layout[4][3][3]; + char project_name[64]; + 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; +}; + +extern int sensor_register_slave(int type, struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)); + + +extern int sensor_unregister_slave(int type, struct i2c_client *client, + struct sensor_platform_data *slave_pdata, + struct sensor_operate *(*get_sensor_ops)(void)); + +#define DBG(x...) + +#define GSENSOR_IOCTL_MAGIC 'a' +#define GBUFF_SIZE 12 /* Rx buffer size */ + +/* IOCTLs for MMA8452 library */ +#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]) +#define GSENSOR_IOCTL_APP_SET_RATE _IOW(GSENSOR_IOCTL_MAGIC, 0x10, short) +#define GSENSOR_IOCTL_GET_CALIBRATION _IOR(GSENSOR_IOCTL_MAGIC, 0x11, int[3]) + + +#define COMPASS_IOCTL_MAGIC 'c' +/* IOCTLs for APPs */ +#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) + +#ifdef CONFIG_COMPAT +#define COMPAT_ECS_IOCTL_APP_SET_MODE _IOW(COMPASS_IOCTL_MAGIC, 0x10, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_SET_MFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x11, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_GET_MFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x12, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_SET_AFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x13, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_GET_AFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x14, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_SET_TFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x15, compat_short_t)/* NOT use */ +#define COMPAT_ECS_IOCTL_APP_GET_TFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x16, compat_short_t)/* NOT use */ +#define COMPAT_ECS_IOCTL_APP_RESET_PEDOMETER _IOW(COMPASS_IOCTL_MAGIC, 0x17) /* NOT use */ +#define COMPAT_ECS_IOCTL_APP_SET_DELAY _IOW(COMPASS_IOCTL_MAGIC, 0x18, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_SET_MVFLAG _IOW(COMPASS_IOCTL_MAGIC, 0x19, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_GET_MVFLAG _IOR(COMPASS_IOCTL_MAGIC, 0x1A, compat_short_t) +#define COMPAT_ECS_IOCTL_APP_GET_DELAY _IOR(COMPASS_IOCTL_MAGIC, 0x1B, compat_short_t) +#endif + +#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_SET_RATE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, short) + +#ifdef CONFIG_COMPAT +#define COMPAT_LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, compat_uptr_t) +#define COMPAT_LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, compat_uptr_t) +#define COMPAT_LIGHTSENSOR_IOCTL_SET_RATE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 3, compat_short_t) +#endif + +#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 *) + +#ifdef CONFIG_COMPAT +#define COMPAT_PSENSOR_IOCTL_GET_ENABLED _IOR(PSENSOR_IOCTL_MAGIC, 1, compat_uptr_t) +#define COMPAT_PSENSOR_IOCTL_ENABLE _IOW(PSENSOR_IOCTL_MAGIC, 2, compat_uptr_t) +#define COMPAT_PSENSOR_IOCTL_DISABLE _IOW(PSENSOR_IOCTL_MAGIC, 3, compat_uptr_t) +#endif + +#define PRESSURE_IOCTL_MAGIC 'r' +#define PRESSURE_IOCTL_GET_ENABLED _IOR(PRESSURE_IOCTL_MAGIC, 1, int *) +#define PRESSURE_IOCTL_ENABLE _IOW(PRESSURE_IOCTL_MAGIC, 2, int *) +#define PRESSURE_IOCTL_DISABLE _IOW(PRESSURE_IOCTL_MAGIC, 3, int *) +#define PRESSURE_IOCTL_SET_DELAY _IOW(PRESSURE_IOCTL_MAGIC, 4, int *) + + +#define TEMPERATURE_IOCTL_MAGIC 't' +#define TEMPERATURE_IOCTL_GET_ENABLED _IOR(TEMPERATURE_IOCTL_MAGIC, 1, int *) +#define TEMPERATURE_IOCTL_ENABLE _IOW(TEMPERATURE_IOCTL_MAGIC, 2, int *) +#define TEMPERATURE_IOCTL_DISABLE _IOW(TEMPERATURE_IOCTL_MAGIC, 3, int *) +#define TEMPERATURE_IOCTL_SET_DELAY _IOW(TEMPERATURE_IOCTL_MAGIC, 4, int *) + + +extern int sensor_rx_data(struct i2c_client *client, char *rxData, int length); +extern int sensor_tx_data(struct i2c_client *client, char *txData, int length); +extern int sensor_write_reg(struct i2c_client *client, int addr, int value); +extern int sensor_read_reg(struct i2c_client *client, int addr); +extern int sensor_tx_data_normal(struct i2c_client *client, char *buf, int num); +extern int sensor_rx_data_normal(struct i2c_client *client, char *buf, int num); +extern int sensor_write_reg_normal(struct i2c_client *client, char value); +extern int sensor_read_reg_normal(struct i2c_client *client); + -- 2.7.4