From c3d4fc608ed75a1ca3cc5a58397e6bf9deef6b24 Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Thu, 19 Nov 2015 12:12:45 +1030 Subject: [PATCH 1/6] drivers: misc: zte-sensor: Add AKM8963, accel mc3xxx, accel bm2xx Used in T792 --- arch/arm/boot/dts/msm8610-qrd.dtsi | 22 + drivers/misc/zte-sensor/Kconfig | 36 +- drivers/misc/zte-sensor/Makefile | 7 + drivers/misc/zte-sensor/akm8963.c | 1722 ++++++++++++++ drivers/misc/zte-sensor/bma2xx.c | 3486 ++++++++++++++++++++++++++++ drivers/misc/zte-sensor/mc3xxx.c | 1944 ++++++++++++++++ include/linux/akm8963.h | 95 + include/linux/bma2xx.h | 691 ++++++ 8 files changed, 7998 insertions(+), 5 deletions(-) create mode 100644 drivers/misc/zte-sensor/akm8963.c create mode 100644 drivers/misc/zte-sensor/bma2xx.c create mode 100644 drivers/misc/zte-sensor/mc3xxx.c create mode 100644 include/linux/akm8963.h create mode 100644 include/linux/bma2xx.h diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi index 252e4ef5cb53..19106611182e 100644 --- a/arch/arm/boot/dts/msm8610-qrd.dtsi +++ b/arch/arm/boot/dts/msm8610-qrd.dtsi @@ -128,6 +128,28 @@ //st,negate-y; //st,negate-z; }; + mc3xxx@4c { + compatible = "mc,mc3xxx"; + reg = <0x4c>; + vdd-supply = <&pm8110_l19>; + vio-supply = <&pm8110_l14>; + gpio-irq-pin = <&msmgpio 81 0>; + mc,axis-map-x = <1>; + mc,axis-map-y = <0>; + mc,axis-map-z = <2>; + mc,negate-z; + }; + bma2xx@18 { + compatible = "bcm,bma2xx"; + reg = <0x18>; + //interrupt-parent = <&msmgpio>; + //interrupts = <81 0x2>; + vdd-supply = <&pm8110_l19>; + vio-supply = <&pm8110_l14>; + bma2xx,gpio-irq1 = <&msmgpio 81 0>; + bma2xx,gpio-irq2 = <&msmgpio 82 0>; + bma2xx,orientation = <6>; + }; taos@39 { compatible = "taos,tmd277x"; reg = <0x39>; diff --git a/drivers/misc/zte-sensor/Kconfig b/drivers/misc/zte-sensor/Kconfig index d714591b0848..1bef412d8465 100644 --- a/drivers/misc/zte-sensor/Kconfig +++ b/drivers/misc/zte-sensor/Kconfig @@ -1,3 +1,7 @@ +# +# TI's shared transport line discipline and the protocol +# drivers (BT, FM and GPS) +# menu "ZTE sensors" config ZTE_SENSORS_ACCEL_LIS3DH tristate "accel lis3dh" @@ -7,9 +11,31 @@ config ZTE_SENSORS_ACCEL_LIS3DH If you say yes here, you just support st accel lis3dh config ZTE_SENSORS_LIGHT_TAOS - tristate "taos light&proximity sensor tmd2771" - depends on I2C - default n - help - Say Y if you want to support tmd2771 light&proximity sensor + tristate "taos light&proximity sensor tmd2771" + depends on I2C + default n + help + Say Y if you want to support tmd2771 light&proximity sensor + +config ZTE_SENSORS_COMPASS_AK8963 + tristate "AK8963 compass support" + depends on I2C + help + If you say yes here you get support for Asahi Kasei's + orientation sensor AK8963. + +config ZTE_SENSORS_ACCEL_MC3XXX + tristate "accel mc3xxx" + depends on I2C + select INPUT_POLLDEV + help + if you say yes here, you just support st accel mc3xxx + +config ZTE_SENSORS_ACCEL_BMA2XX + tristate "accel bma2xx" + depends on I2C + select INPUT_POLLDEV + help + if you say yes here, you just support st accel bma2xx + endmenu diff --git a/drivers/misc/zte-sensor/Makefile b/drivers/misc/zte-sensor/Makefile index 66f6f32ddfcb..1daf62057093 100644 --- a/drivers/misc/zte-sensor/Makefile +++ b/drivers/misc/zte-sensor/Makefile @@ -1,2 +1,9 @@ +# +# Makefile for TI's shared transport line discipline +# and its protocol drivers (BT, FM, GPS) +# obj-$(CONFIG_ZTE_SENSORS_ACCEL_LIS3DH) += lis3dh_acc.o obj-$(CONFIG_ZTE_SENSORS_LIGHT_TAOS) += taos.o +obj-$(CONFIG_ZTE_SENSORS_ACCEL_MC3XXX) += mc3xxx.o +obj-$(CONFIG_ZTE_SENSORS_ACCEL_BMA2XX) += bma2xx.o +obj-$(CONFIG_ZTE_SENSORS_COMPASS_AK8963) += akm8963.o \ No newline at end of file diff --git a/drivers/misc/zte-sensor/akm8963.c b/drivers/misc/zte-sensor/akm8963.c new file mode 100644 index 000000000000..a561650e66e5 --- /dev/null +++ b/drivers/misc/zte-sensor/akm8963.c @@ -0,0 +1,1722 @@ +/* drivers/misc/akm8963.c - akm8963 compass driver + * + * Copyright (C) 2007-2008 HTC Corporation. + * Author: Hou-Kun Chen + * + * 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. + * + */ + +/*#define DEBUG*/ +/*#define VERBOSE_DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//yaotierui +#include +#include +#include // added by yangze for create proc file 20121011 +#define AKM8963_DEBUG_IF 0 +#define AKM8963_DEBUG_DATA 0 + +#define AKM_ACCEL_ITEMS 3 +/* Wait timeout in millisecond */ +#define AKM8963_DRDY_TIMEOUT 100 + +struct akm8963_data { + struct i2c_client *i2c; + struct input_dev *input; + struct device *class_dev; + struct class *compass; + struct delayed_work work; + + wait_queue_head_t drdy_wq; + wait_queue_head_t open_wq; + + struct mutex sensor_mutex; + int8_t sense_data[SENSOR_DATA_SIZE]; + struct mutex accel_mutex; + int16_t accel_data[AKM_ACCEL_ITEMS]; + + struct mutex val_mutex; + uint32_t enable_flag; + int64_t delay[AKM_NUM_SENSORS]; + + atomic_t active; + atomic_t is_busy; + atomic_t drdy; + atomic_t suspend; + + char layout; + char outbit; + int irq; + int rstn; +#ifdef CONFIG_OF + bool vdd_enabled; + bool vio_enabled; + struct regulator *vdd; + struct regulator *vio; +#endif +}; + +static struct akm8963_data *s_akm; + +static int chipid=0xff; +#ifdef CONFIG_OF +#define AKM_VDD_MIN_UV 2700000 +#define AKM_VDD_MAX_UV 3300000 +#define AKM_VIO_MIN_UV 1700000 +#define AKM_VIO_MAX_UV 2000000 +#endif + +/***** I2C I/O function ***********************************************/ +static int akm8963_i2c_rxdata( + struct i2c_client *i2c, + unsigned char *rxData, + int length) +{ + struct i2c_msg msgs[] = { + { + .addr = i2c->addr, + .flags = 0, + .len = 1, + .buf = rxData, + }, + { + .addr = i2c->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxData, + }, }; + unsigned char addr = rxData[0]; + + if (i2c_transfer(i2c->adapter, msgs, 2) < 0) { + dev_err(&i2c->dev, "%s: transfer failed.", __func__); + return -EIO; + } + + dev_vdbg(&i2c->dev, "RxData: len=%02x, addr=%02x, data=%02x", + length, addr, rxData[0]); + return 0; +} + +static int akm8963_i2c_txdata( + struct i2c_client *i2c, + unsigned char *txData, + int length) +{ + struct i2c_msg msg[] = { + { + .addr = i2c->addr, + .flags = 0, + .len = length, + .buf = txData, + }, }; + + if (i2c_transfer(i2c->adapter, msg, 1) < 0) { + dev_err(&i2c->dev, "%s: transfer failed.", __func__); + return -EIO; + } + + dev_vdbg(&i2c->dev, "TxData: len=%02x, addr=%02x data=%02x", + length, txData[0], txData[1]); + return 0; +} + +static int akm8963_i2c_check_device( + struct i2c_client *client) +{ + unsigned char buffer[2]; + int err; + + /* Set measure mode */ + buffer[0] = AK8963_REG_WIA; + err = akm8963_i2c_rxdata(client, buffer, 1); + if (err < 0) { + dev_err(&client->dev, + "%s: Can not read WIA.", __func__); + return err; + } + + /* Check read data */ + if (buffer[0] != 0x48) { + dev_err(&client->dev, + "%s: The device is not AK8963.", __func__); + return -ENXIO; + } + + chipid = buffer[0]; + return err; +} + +/***** akm miscdevice functions *************************************/ +static int AKECS_Open(struct inode *inode, struct file *file); +static int AKECS_Release(struct inode *inode, struct file *file); +static long AKECS_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +static struct file_operations AKECS_fops = { + .owner = THIS_MODULE, + .open = AKECS_Open, + .release = AKECS_Release, + .unlocked_ioctl = AKECS_ioctl, +}; + +static struct miscdevice akm8963_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "akm8963_dev", + .fops = &AKECS_fops, +}; + +static int AKECS_Set_CNTL1( + struct akm8963_data *akm, + unsigned char mode) +{ + unsigned char buffer[2]; + int err; + + /* Busy check */ + if (atomic_cmpxchg(&akm->is_busy, 0, 1) != 0) { + dev_err(&akm->i2c->dev, "%s: device is busy.", __func__); + return -EBUSY; + } + + /* Set flag */ + atomic_set(&akm->drdy, 0); + + /* Set measure mode */ + buffer[0] = AK8963_REG_CNTL1; + buffer[1] = mode; + err = akm8963_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, "%s: Can not set CNTL.", __func__); + atomic_set(&akm->is_busy, 0); + } else { + dev_dbg(&akm->i2c->dev, "Mode is set to (%d).", mode); + } + + return err; +} + +static int AKECS_Set_PowerDown( + struct akm8963_data *akm) +{ + unsigned char buffer[2]; + int err; + + /* Set measure mode */ + buffer[0] = AK8963_REG_CNTL1; + buffer[1] = AK8963_MODE_POWERDOWN; + err = akm8963_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: Can not set to measurement mode.", __func__); + atomic_set(&akm->is_busy, 0); + } else { + dev_dbg(&akm->i2c->dev, "Powerdown mode is set."); + } + + /* Set to initial status. */ + atomic_set(&akm->is_busy, 0); + atomic_set(&akm->drdy, 0); + + return err; +} + +static int AKECS_Reset( + struct akm8963_data *akm, + int hard) +{ + unsigned char buffer[2]; + int err = 0; + + if (hard != 0) { + printk("akm8963 gose to reset!"); + gpio_direction_output(akm->rstn, 0); + udelay(5); + gpio_direction_output(akm->rstn, 1); + } else { + /* Set measure mode */ + buffer[0] = AK8963_REG_CNTL2; + buffer[1] = 0x01; + err = akm8963_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: Can not set SRST bit.", __func__); + } else { + dev_dbg(&akm->i2c->dev, "Soft reset is done."); + } + } + + /* Device will be accessible 100 us after */ + udelay(100); + + return err; +} + +static int AKECS_SetMode( + struct akm8963_data *akm, + unsigned char mode) +{ + int err; + + switch (mode & 0x0F) { + case AK8963_MODE_SNG_MEASURE: + case AK8963_MODE_SELF_TEST: + case AK8963_MODE_FUSE_ACCESS: + err = AKECS_Set_CNTL1(akm, mode); + if ((err >= 0) && (akm->irq == 0)) { + schedule_delayed_work( + &akm->work, + usecs_to_jiffies(AK8963_MEASUREMENT_TIME_US)); + } + break; + case AK8963_MODE_POWERDOWN: + err = AKECS_Set_PowerDown(akm); + break; + default: + dev_err(&akm->i2c->dev, + "%s: Unknown mode(%d).", __func__, mode); + return -EINVAL; + } + + /* wait at least 100us after changing mode */ + udelay(100); + + return err; +} + +/* This function will block a process until the latest measurement + * data is available. + */ +static int AKECS_GetData( + struct akm8963_data *akm, + char *rbuf, + int size) +{ + int err; + err = wait_event_interruptible_timeout( + akm->drdy_wq, + atomic_read(&akm->drdy), + AKM8963_DRDY_TIMEOUT); + + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: wait_event failed (%d).", __func__, err); + return -1; + } + if (!atomic_read(&akm->drdy)) { + dev_err(&akm->i2c->dev, + "%s: DRDY is not set.", __func__); + return -1; + } + + mutex_lock(&akm->sensor_mutex); + memcpy(rbuf, akm->sense_data, size); + atomic_set(&akm->drdy, 0); + mutex_unlock(&akm->sensor_mutex); + + return 0; +} + +static void AKECS_SetYPR( + struct akm8963_data *akm, + int *rbuf) +{ + uint32_t ready; + dev_vdbg(&akm->i2c->dev, "AKM8963 %s: flag =0x%X", __func__, + rbuf[0]); + dev_vdbg(&akm->input->dev, " Acceleration[LSB]: %6d,%6d,%6d stat=%d", + rbuf[1], rbuf[2], rbuf[3], rbuf[4]); + dev_vdbg(&akm->input->dev, " Geomagnetism[LSB]: %6d,%6d,%6d stat=%d", + rbuf[5], rbuf[6], rbuf[7], rbuf[8]); + dev_vdbg(&akm->input->dev, " Orientation[YPR] : %6d,%6d,%6d", + rbuf[9], rbuf[10], rbuf[11]); + + /* No events are reported */ + if (!rbuf[0]) { + dev_dbg(&akm->i2c->dev, "Don't waste a time."); + return; + } + + mutex_lock(&akm->val_mutex); + ready = (akm->enable_flag & (uint32_t)rbuf[0]); + mutex_unlock(&akm->val_mutex); + + /* Report acceleration sensor information */ + if (ready & ACC_DATA_READY) { + input_report_abs(akm->input, ABS_X, rbuf[1]); + input_report_abs(akm->input, ABS_Y, rbuf[2]); + input_report_abs(akm->input, ABS_Z, rbuf[3]); + input_report_abs(akm->input, ABS_THROTTLE, rbuf[4]); + } + /* Report magnetic vector information */ + if (ready & MAG_DATA_READY) { + input_report_abs(akm->input, ABS_RX, rbuf[5]); + input_report_abs(akm->input, ABS_RY, rbuf[6]); + input_report_abs(akm->input, ABS_RZ, rbuf[7]); + input_report_abs(akm->input, ABS_RUDDER, rbuf[8]); + } + /* Report orientation sensor information */ + if (ready & ORI_DATA_READY) { + input_report_abs(akm->input, ABS_HAT0X, rbuf[9]); + input_report_abs(akm->input, ABS_HAT0Y, rbuf[10]); + input_report_abs(akm->input, ABS_HAT1X, rbuf[11]); + input_report_abs(akm->input, ABS_HAT1Y, rbuf[4]); + } + + input_sync(akm->input); +} + +static int AKECS_GetOpenStatus( + struct akm8963_data *akm) +{ + return wait_event_interruptible( + akm->open_wq, (atomic_read(&akm->active) != 0)); +} + +static int AKECS_GetCloseStatus( + struct akm8963_data *akm) +{ + return wait_event_interruptible( + akm->open_wq, (atomic_read(&akm->active) <= 0)); +} + +static int AKECS_Open(struct inode *inode, struct file *file) +{ + file->private_data = s_akm; + return nonseekable_open(inode, file); +} + +static int AKECS_Release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long +AKECS_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct akm8963_data *akm = file->private_data; + + /* NOTE: In this function the size of "char" should be 1-byte. */ + char i2c_buf[RWBUF_SIZE]; /* for READ/WRITE */ + 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 mode; /* for SET_MODE*/ + char layout; /* for GET_LAYOUT */ + char outbit; /* for GET_OUTBIT */ + int status; /* for OPEN/CLOSE_STATUS */ + int ret = -1; /* Return value. */ + + switch (cmd) { + case ECS_IOCTL_READ: + case ECS_IOCTL_WRITE: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&i2c_buf, argp, sizeof(i2c_buf))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_SET_MODE: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&mode, argp, sizeof(mode))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_SET_YPR: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&ypr_buf, argp, sizeof(ypr_buf))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + 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) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + break; + break; + default: + break; + } + + switch (cmd) { + case ECS_IOCTL_READ: + dev_vdbg(&akm->i2c->dev, "IOCTL_READ called."); + if ((i2c_buf[0] < 1) || (i2c_buf[0] > (RWBUF_SIZE-1))) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + ret = akm8963_i2c_rxdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_WRITE: + dev_vdbg(&akm->i2c->dev, "IOCTL_WRITE called."); + if ((i2c_buf[0] < 2) || (i2c_buf[0] > (RWBUF_SIZE-1))) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + ret = akm8963_i2c_txdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_SET_MODE: + dev_vdbg(&akm->i2c->dev, "IOCTL_SET_MODE called."); + ret = AKECS_SetMode(akm, mode); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_GETDATA: + dev_vdbg(&akm->i2c->dev, "IOCTL_GETDATA called."); + ret = AKECS_GetData(akm, sensor_buf, SENSOR_DATA_SIZE); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_SET_YPR: + dev_vdbg(&akm->i2c->dev, "IOCTL_SET_YPR called."); + AKECS_SetYPR(akm, ypr_buf); + break; + case ECS_IOCTL_GET_OPEN_STATUS: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_OPEN_STATUS called."); + ret = AKECS_GetOpenStatus(akm); + if (ret < 0) { + //dev_err(&akm->i2c->dev,"Get Open returns error (%d).", ret); + } + break; + case ECS_IOCTL_GET_CLOSE_STATUS: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_CLOSE_STATUS called."); + ret = AKECS_GetCloseStatus(akm); + if (ret < 0) { + //dev_err(&akm->i2c->dev, "Get Close returns error (%d).", ret); + } + break; + case ECS_IOCTL_GET_DELAY: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_DELAY called."); + mutex_lock(&akm->val_mutex); + delay[0] = akm->delay[0]; + delay[1] = akm->delay[1]; + delay[2] = akm->delay[2]; + mutex_unlock(&akm->val_mutex); + break; + case ECS_IOCTL_GET_LAYOUT: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_LAYOUT called."); + layout = akm->layout; + break; + case ECS_IOCTL_GET_OUTBIT: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_OUTBIT called."); + outbit = akm->outbit; + break; + case ECS_IOCTL_RESET: + ret = AKECS_Reset(akm, akm->rstn); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_GET_ACCEL: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_ACCEL called."); + mutex_lock(&akm->accel_mutex); + acc_buf[0] = akm->accel_data[0]; + acc_buf[1] = akm->accel_data[1]; + acc_buf[2] = akm->accel_data[2]; + mutex_unlock(&akm->accel_mutex); + break; + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_READ: + if (copy_to_user(argp, &i2c_buf, i2c_buf[0]+1)) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GETDATA: + if (copy_to_user(argp, &sensor_buf, sizeof(sensor_buf))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + status = atomic_read(&akm->active); + if (copy_to_user(argp, &status, sizeof(status))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_DELAY: + if (copy_to_user(argp, &delay, sizeof(delay))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_LAYOUT: + if (copy_to_user(argp, &layout, sizeof(layout))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OUTBIT: + if (copy_to_user(argp, &outbit, sizeof(outbit))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_ACCEL: + if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + default: + break; + } + + return 0; +} + +/***** akm sysfs functions ******************************************/ +static int create_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + int err = 0; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_device_binary_attributes( + struct kobject *kobj, + struct bin_attribute *attrs) +{ + int i; + int err = 0; + + err = 0; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = sysfs_create_bin_file(kobj, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + sysfs_remove_bin_file(kobj, &attrs[i]); + } + + return err; +} + +static void remove_device_binary_attributes( + struct kobject *kobj, + struct bin_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + sysfs_remove_bin_file(kobj, &attrs[i]); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value) +{ + long tmp; + + if (size == 0) + return false; + + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + + return true; +} + +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + + if (size == 0) + return false; + + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + + return true; +} + +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/compass/akm8963/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - enable_mag [rw] [t] : enable flag for magnetometer + * - enable_ori [rw] [t] : enable flag for orientation + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - delay_mag [rw] [t] : delay in nanosecond for magnetometer + * - delay_ori [rw] [t] : delay in nanosecond for orientation + * - accel [w] [b] : accelerometer data + * + * debug : + * - mode [w] [t] : AK8963's mode + * - bdata [r] [t] : raw data + * - asa [r] [t] : FUSEROM data + * + * [b] = binary format + * [t] = text format + */ + +/***** sysfs enable *************************************************/ +static void akm8963_sysfs_update_active_status( + struct akm8963_data *akm) +{ + uint32_t en; + mutex_lock(&akm->val_mutex); + en = akm->enable_flag; + mutex_unlock(&akm->val_mutex); + + if (en == 0) { + if (atomic_cmpxchg(&akm->active, 1, 0) == 1) { + wake_up(&akm->open_wq); + dev_dbg(akm->class_dev, "Deactivated"); + } + } else { + if (atomic_cmpxchg(&akm->active, 0, 1) == 0) { + wake_up(&akm->open_wq); + dev_dbg(akm->class_dev, "Activated"); + } + } + dev_dbg(&akm->i2c->dev, + "Status updated: enable=0x%X, active=%d", + en, atomic_read(&akm->active)); +} + +static ssize_t akm8963_sysfs_enable_show( + struct akm8963_data *akm, char *buf, int pos) +{ + int flag; + + mutex_lock(&akm->val_mutex); + flag = ((akm->enable_flag >> pos) & 1); + mutex_unlock(&akm->val_mutex); + + return sprintf(buf, "%d\n", flag); +} + +static ssize_t akm8963_sysfs_enable_store( + struct akm8963_data *akm, char const *buf, size_t count, int pos) +{ + int en = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + mutex_lock(&akm->val_mutex); + akm->enable_flag &= ~(1<enable_flag |= ((uint32_t)(en))<val_mutex); + + akm8963_sysfs_update_active_status(akm); + + return count; +} + +/***** Acceleration ***/ +static ssize_t akm8963_enable_acc_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_enable_show( + dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} +static ssize_t akm8963_enable_acc_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** Magnetic field ***/ +static ssize_t akm8963_enable_mag_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_enable_show( + dev_get_drvdata(dev), buf, MAG_DATA_FLAG); +} +static ssize_t akm8963_enable_mag_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); +} + +/***** Orientation ***/ +static ssize_t akm8963_enable_ori_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_enable_show( + dev_get_drvdata(dev), buf, ORI_DATA_FLAG); +} +static ssize_t akm8963_enable_ori_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, ORI_DATA_FLAG); +} + +/***** sysfs delay **************************************************/ +static ssize_t akm8963_sysfs_delay_show( + struct akm8963_data *akm, char *buf, int pos) +{ + int64_t val; + + mutex_lock(&akm->val_mutex); + val = akm->delay[pos]; + mutex_unlock(&akm->val_mutex); + + return sprintf(buf, "%lld\n", val); +} + +static ssize_t akm8963_sysfs_delay_store( + struct akm8963_data *akm, char const *buf, size_t count, int pos) +{ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + mutex_lock(&akm->val_mutex); + akm->delay[pos] = val; + mutex_unlock(&akm->val_mutex); + + return count; +} + +/***** Accelerometer ***/ +static ssize_t akm8963_delay_acc_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_delay_show( + dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} +static ssize_t akm8963_delay_acc_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** Magnetic field ***/ +static ssize_t akm8963_delay_mag_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_delay_show( + dev_get_drvdata(dev), buf, MAG_DATA_FLAG); +} +static ssize_t akm8963_delay_mag_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); +} + +/***** Orientation ***/ +static ssize_t akm8963_delay_ori_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm8963_sysfs_delay_show( + dev_get_drvdata(dev), buf, ORI_DATA_FLAG); +} +static ssize_t akm8963_delay_ori_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm8963_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, ORI_DATA_FLAG); +} + + +/***** accel (binary) ***/ +static ssize_t akm8963_bin_accel_write( + struct file *file, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, + loff_t pos, + size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct akm8963_data *akm = dev_get_drvdata(dev); + int16_t *accel_data; + + if (size == 0) + return 0; + + accel_data = (int16_t*)buf; + + mutex_lock(&akm->accel_mutex); + akm->accel_data[0] = accel_data[0]; + akm->accel_data[1] = accel_data[1]; + akm->accel_data[2] = accel_data[2]; + mutex_unlock(&akm->accel_mutex); + + dev_vdbg(&akm->i2c->dev, "accel:%d,%d,%d\n", + accel_data[0], accel_data[1], accel_data[2]); + + return size; +} + + +#ifdef AKM8963_DEBUG_IF +static ssize_t akm8963_mode_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + struct akm8963_data *akm = dev_get_drvdata(dev); + int mode = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &mode)) + return -EINVAL; + + if (AKECS_SetMode(akm, mode) < 0) + return -EINVAL; + + return 1; +} + +static ssize_t akm8963_bdata_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct akm8963_data *akm = dev_get_drvdata(dev); + char rbuf[SENSOR_DATA_SIZE]; + + mutex_lock(&akm->sensor_mutex); + memcpy(&rbuf, akm->sense_data, sizeof(rbuf)); + mutex_unlock(&akm->sensor_mutex); + + return sprintf(buf, + "0x%02X,0x%02X,0x%02X,0x%02X," + "0x%02X,0x%02X,0x%02X,0x%02X\n", + rbuf[0],rbuf[1],rbuf[2],rbuf[3], + rbuf[4],rbuf[5],rbuf[6],rbuf[7]); +} + +static ssize_t akm8963_asa_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct akm8963_data *akm = dev_get_drvdata(dev); + int err; + unsigned char asa[3]; + + err = AKECS_SetMode(akm, AK8963_MODE_FUSE_ACCESS); + if (err < 0) + return err; + + asa[0] = AK8963_FUSE_ASAX; + err = akm8963_i2c_rxdata(akm->i2c, asa, 3); + if (err < 0) + return err; + + err = AKECS_SetMode(akm, AK8963_MODE_POWERDOWN); + if (err < 0) + return err; + + return sprintf(buf, "0x%02X,0x%02X,0x%02X\n", + asa[0], asa[1], asa[2]); +} +#endif + +static struct device_attribute akm8963_attributes[] = { + __ATTR(enable_acc, 0660, akm8963_enable_acc_show, akm8963_enable_acc_store), + __ATTR(enable_mag, 0660, akm8963_enable_mag_show, akm8963_enable_mag_store), + __ATTR(enable_ori, 0660, akm8963_enable_ori_show, akm8963_enable_ori_store), + __ATTR(delay_acc, 0660, akm8963_delay_acc_show, akm8963_delay_acc_store), + __ATTR(delay_mag, 0660, akm8963_delay_mag_show, akm8963_delay_mag_store), + __ATTR(delay_ori, 0660, akm8963_delay_ori_show, akm8963_delay_ori_store), +#ifdef AKM8963_DEBUG_IF + __ATTR(mode, 0220, NULL, akm8963_mode_store), + __ATTR(bdata, 0440, akm8963_bdata_show, NULL), + __ATTR(asa, 0440, akm8963_asa_show, NULL), +#endif + __ATTR_NULL, +}; +// added by yangze 20120901 start +static struct device_attribute akm8963_attributes_client[] = { + + __ATTR(enable_device, 0660, akm8963_enable_mag_show, akm8963_enable_mag_store), + __ATTR(pollrate_ms, 0660, akm8963_delay_mag_show, akm8963_delay_mag_store), + __ATTR_NULL, +}; +//added by yangze 20120901 end + +#define __BIN_ATTR(name_, mode_, size_, private_, read_, write_) \ + { \ + .attr = { .name = __stringify(name_), .mode = mode_ }, \ + .size = size_, \ + .private = private_, \ + .read = read_, \ + .write = write_, \ + } + +#define __BIN_ATTR_NULL \ + { \ + .attr = { .name = NULL }, \ + } + +static struct bin_attribute akm8963_bin_attributes[] = { + __BIN_ATTR(accel, 0220, 6, NULL, + NULL, akm8963_bin_accel_write), + __BIN_ATTR_NULL +}; + +static char const *const compass_class_name = "compass"; +static char const *const akm8963_device_name = "akm8963"; +static char const *const device_link_name = "i2c"; +static dev_t const akm8963_device_dev_t = MKDEV(MISC_MAJOR, 240); + +static int create_sysfs_interfaces(struct akm8963_data *akm) +{ + int err; + + if (NULL == akm) + return -EINVAL; + + err = 0; + + akm->compass = class_create(THIS_MODULE, compass_class_name); + if (IS_ERR(akm->compass)) { + err = PTR_ERR(akm->compass); + goto exit_class_create_failed; + } + + akm->class_dev = device_create( + akm->compass, + NULL, + akm8963_device_dev_t, + akm, + akm8963_device_name); + if (IS_ERR(akm->class_dev)) { + err = PTR_ERR(akm->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &akm->class_dev->kobj, + &akm->i2c->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + akm->class_dev, + akm8963_attributes); + // added by yangze 20120901 start + err = create_device_attributes( + &(akm->i2c->dev), + akm8963_attributes_client); + // added by yangze 20120901 end + + if (0 > err) + goto exit_device_attributes_create_failed; + + err = create_device_binary_attributes( + &akm->class_dev->kobj, + akm8963_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; + + return err; + +exit_device_binary_attributes_create_failed: + remove_device_attributes(akm->class_dev, akm8963_attributes); +exit_device_attributes_create_failed: + sysfs_remove_link(&akm->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(akm->compass, akm8963_device_dev_t); +exit_class_device_create_failed: + akm->class_dev = NULL; + class_destroy(akm->compass); +exit_class_create_failed: + akm->compass = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct akm8963_data *akm) +{ + if (NULL == akm) + return; + + if (NULL != akm->class_dev) { + remove_device_binary_attributes( + &akm->class_dev->kobj, + akm8963_bin_attributes); + remove_device_attributes( + akm->class_dev, + akm8963_attributes); + sysfs_remove_link( + &akm->class_dev->kobj, + device_link_name); + akm->class_dev = NULL; + } + if (NULL != akm->compass) { + device_destroy( + akm->compass, + akm8963_device_dev_t); + class_destroy(akm->compass); + akm->compass = NULL; + } +} + + +/***** akm input device functions ***********************************/ +static int akm8963_input_init( + struct input_dev **input) +{ + int err = 0; + + /* Declare input device */ + *input = input_allocate_device(); + if (!*input) + return -ENOMEM; + + /* Setup input device */ + set_bit(EV_ABS, (*input)->evbit); + /* Accelerometer (720 x 16G)*/ + input_set_abs_params(*input, ABS_X, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_Y, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_Z, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_THROTTLE, + 0, 3, 0, 0); + /* Magnetic field (-81900, 81900) -> limited to 16bit*/ + input_set_abs_params(*input, ABS_RX, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_RY, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_RZ, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_RUDDER, + 0, 3, 0, 0); + /* Orientation (yaw:0,360 pitch:-180,180 roll:-90,90) */ + input_set_abs_params(*input, ABS_HAT0X, + 0, 23040, 0, 0); + input_set_abs_params(*input, ABS_HAT0Y, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_HAT1X, + -5760, 5760, 0, 0); + input_set_abs_params(*input, ABS_HAT1Y, + 0, 3, 0, 0); + + /* Set name */ + (*input)->name = "compass"; + + /* Register */ + err = input_register_device(*input); + if (err) { + input_free_device(*input); + return err; + } + + return err; +} + +/***** akm functions ************************************************/ + +static irqreturn_t akm8963_irq(int irq, void *handle) +{ + struct akm8963_data *akm = handle; + char buffer[SENSOR_DATA_SIZE]; + int err; + + memset(buffer, 0, sizeof(buffer)); + buffer[0] = AK8963_REG_ST1; + err = akm8963_i2c_rxdata(akm->i2c, buffer, SENSOR_DATA_SIZE); + if (err < 0) { + dev_err(&akm->i2c->dev, "%s failed.", __func__); + goto work_func_end; + } + /* Check ST bit */ + if ((buffer[0] & 0x01) != 0x01) { + dev_err(&akm->i2c->dev, "%s ST is not set.", __func__); + goto work_func_end; + } + + mutex_lock(&akm->sensor_mutex); + memcpy(akm->sense_data, buffer, SENSOR_DATA_SIZE); + mutex_unlock(&akm->sensor_mutex); + + atomic_set(&akm->drdy, 1); + atomic_set(&akm->is_busy, 0); + wake_up(&akm->drdy_wq); + +work_func_end: + return IRQ_HANDLED; +} + +static void akm8963_delayed_work(struct work_struct *work) +{ + struct akm8963_data *akm = container_of( + work, struct akm8963_data, work.work); + + akm8963_irq(akm->irq, akm); +} + +static int akm8963_suspend(struct device *dev) +{ + struct akm8963_data *akm = dev_get_drvdata(dev); + dev_dbg(&akm->i2c->dev, "suspended\n"); + + return 0; +} + +static int akm8963_resume(struct device *dev) +{ + struct akm8963_data *akm = dev_get_drvdata(dev); + dev_dbg(&akm->i2c->dev, "resumed\n"); + + return 0; +} + +#ifdef CONFIG_OF +static int akm_parse_dt(struct device *dev, struct akm8963_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + rc = of_property_read_u32(np, "akm,layout", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read layout\n"); + return rc; + } else { + pdata->layout = temp_val; + } + + rc = of_property_read_u32(np, "akm,outbit", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read outbit\n"); + return rc; + } else { + pdata->outbit = temp_val; + } + + temp_val = of_get_named_gpio(np, "akm,gpio-rstn", 0); + if (temp_val < 0) { + dev_err(dev, "Unable to read gpio_rstn\n"); + } else { + pdata->gpio_RST = temp_val; + } + + temp_val = of_get_named_gpio(np, "akm,gpio-drdy", 0); + if (gpio_is_valid(temp_val)) { + rc = gpio_request(temp_val, "akm_drdy"); + if (rc) { + dev_err(dev, "reset gpio request failed"); + } + gpio_direction_input(temp_val); + } + + return 0; +} + +static int akm_power_init(struct akm8963_data *data, bool on) +{ + int rc; + int vol_uv; + int enabled = 0; + + if (!on) { + if (data->vdd_enabled) { + regulator_disable(data->vdd); + data->vdd_enabled = false; + } + if (data->vio_enabled) { + regulator_disable(data->vio); + data->vio_enabled = false; + } + + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, AKM_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, 0, AKM_VIO_MAX_UV); + + regulator_put(data->vio); + } else { + data->vdd = regulator_get(&data->i2c->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->i2c->dev, + "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + vol_uv = regulator_get_voltage(data->vdd); + enabled = regulator_is_enabled(data->vdd); + dev_info(&data->i2c->dev, "vdd current voltate is %duv, enabled = %d ", vol_uv, enabled); + if ((vol_uv >= AKM_VDD_MIN_UV) && (vol_uv <= AKM_VDD_MAX_UV)) { + dev_info(&data->i2c->dev,"no need to set vdd voltage again"); + } else if (regulator_count_voltages(data->vdd) > 0) { + rc = regulator_set_voltage(data->vdd, AKM_VDD_MIN_UV, + AKM_VDD_MAX_UV); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator set failed vdd rc=%d\n", + rc); + goto reg_vdd_put; + } + } + if (enabled == 1) { + dev_info(&data->i2c->dev,"no need to enable vdd voltage again"); + } else if (!data->vdd_enabled) { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vdd enable failed rc=%d\n", rc); + goto reg_vdd_put; + } + data->vdd_enabled = true; + } + + data->vio = regulator_get(&data->i2c->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->i2c->dev, + "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_dis; + } + + vol_uv = regulator_get_voltage(data->vio); + enabled = regulator_is_enabled(data->vio); + dev_info(&data->i2c->dev, "vio current voltate is %duv, enabled = %d ", vol_uv, enabled); + if ((vol_uv >= AKM_VIO_MIN_UV) && (vol_uv <= AKM_VIO_MAX_UV)) { + dev_info(&data->i2c->dev,"no need to set vio voltage again"); + } else if (regulator_count_voltages(data->vio) > 0) { + rc = regulator_set_voltage(data->vio, AKM_VIO_MIN_UV, + AKM_VIO_MAX_UV); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + if (enabled == 1) { + dev_info(&data->i2c->dev,"no need to enable vio voltage again"); + } else if (!data->vio_enabled) { + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vio enable failed rc=%d\n", rc); + goto reg_vio_put; + } + data->vio_enabled = true; + msleep(10); + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_dis: + if (data->vdd_enabled){ + regulator_disable(data->vdd); + data->vdd_enabled = false; + } +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} +#else +static int akm_parse_dt(struct device *dev, struct akm8963_platform_data *pdata) +{ + return -ENODEV; +} +static int akm_power_init(struct akm8963_data *data, bool on) +{ + return 0; +} +#endif + +int akm8963_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct akm8963_platform_data *pdata; + int err = 0; + int i; + + dev_dbg(&client->dev, "start probing."); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "%s: check_functionality failed.", __func__); + err = -ENODEV; + goto exit0; + } + + /* Allocate memory for driver data */ + s_akm = kzalloc(sizeof(struct akm8963_data), GFP_KERNEL); + if (!s_akm) { + dev_err(&client->dev, "%s: memory allocation failed.", __func__); + err = -ENOMEM; + goto exit1; + } + + /***** Set layout information *****/ + if (client->dev.of_node) { + printk("akm8963 use device tree\n"); + pdata = devm_kzalloc(&client->dev, sizeof(struct akm8963_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + goto exit2; + } + err = akm_parse_dt(&client->dev, pdata); + if (err) { + dev_err(&client->dev, + "Unable to parse platfrom data err=%d\n", err); + goto exit2; + } + } else { + printk("akm8963 not use device tree\n"); + pdata = client->dev.platform_data; + } + + printk("akm irq = %d\n", client->irq); + + if (pdata) { + /* Platform data is available. copy its value to local. */ + s_akm->layout = pdata->layout; + s_akm->outbit = pdata->outbit; + s_akm->rstn = pdata->gpio_RST; + } else { + /* Platform data is not available. + Layout and Outbit information should be set by each application. */ + dev_dbg(&client->dev, "%s: No platform data.", __func__); + s_akm->layout = 0; + s_akm->outbit = 0; + s_akm->rstn = 0; + } + + /***** I2C initialization *****/ + s_akm->i2c = client; + + s_akm->vdd_enabled = false; + s_akm->vio_enabled = false; + err = akm_power_init(s_akm, true); + if (err < 0) { + dev_err(&s_akm->i2c->dev, "power init failed! err=%d", err); + goto exit2; + } + + if (gpio_is_valid(s_akm->rstn)) { + err = gpio_request(s_akm->rstn, "akm_rstn"); + if (err) { + dev_err(&client->dev, "reset gpio request failed"); + goto exit2_1; + } + AKECS_Reset(s_akm, 1); + } + + /* check connection */ + err = akm8963_i2c_check_device(client); + if (err < 0) + goto exit3; + /* set client data */ + i2c_set_clientdata(client, s_akm); + + + /***** input *****/ + err = akm8963_input_init(&s_akm->input); + if (err) { + dev_err(&client->dev, + "%s: input_dev register failed", __func__); + goto exit3; + } + input_set_drvdata(s_akm->input, s_akm); + + + /**** initialize variables in akm8963_data *****/ + init_waitqueue_head(&s_akm->drdy_wq); + init_waitqueue_head(&s_akm->open_wq); + + mutex_init(&s_akm->sensor_mutex); + mutex_init(&s_akm->accel_mutex); + mutex_init(&s_akm->val_mutex); + + atomic_set(&s_akm->active, 0); + atomic_set(&s_akm->is_busy, 0); + atomic_set(&s_akm->drdy, 0); + atomic_set(&s_akm->suspend, 0); + + s_akm->enable_flag = 0; + for (i=0; idelay[i] = -1; + // added by yangze 20120903 start + if(1 == i){ + s_akm->delay[1] = 200; + } + // added by yangze 20120903 end + } + + /***** IRQ setup *****/ + s_akm->irq = client->irq; + + if (s_akm->irq == 0) { + dev_dbg(&client->dev, "%s: IRQ is not set.", __func__); + /* Use timer to notify measurement end */ + INIT_DELAYED_WORK(&s_akm->work, akm8963_delayed_work); + } else { + err = request_threaded_irq( + s_akm->irq, + NULL, + akm8963_irq, + IRQF_TRIGGER_HIGH|IRQF_ONESHOT, + dev_name(&client->dev), + s_akm); + if (err < 0) { + dev_err(&client->dev, + "%s: request irq failed.", __func__); + goto exit4; + } + } + + /***** misc *****/ + err = misc_register(&akm8963_dev); + if (err) { + dev_err(&client->dev, + "%s: akm8963_dev register failed", __func__); + goto exit5; + } + + /***** sysfs *****/ + err = create_sysfs_interfaces(s_akm); + if (0 > err) { + dev_err(&client->dev, + "%s: create sysfs failed.", __func__); + goto exit6; + } + + dev_info(&client->dev, "successfully probed."); + return 0; + +exit6: + misc_deregister(&akm8963_dev); +exit5: + if (s_akm->irq) + free_irq(s_akm->irq, s_akm); +exit4: + input_unregister_device(s_akm->input); +exit3: +exit2_1: + akm_power_init(s_akm,false); +exit2: + kfree(s_akm); +exit1: +exit0: + return err; +} + +static int akm8963_remove(struct i2c_client *client) +{ + struct akm8963_data *akm = i2c_get_clientdata(client); + + remove_sysfs_interfaces(akm); + if (misc_deregister(&akm8963_dev) < 0) + dev_err(&client->dev, "misc deregister failed."); + if (akm->irq) + free_irq(akm->irq, akm); + input_unregister_device(akm->input); + akm_power_init(s_akm,false); + kfree(akm); + dev_info(&client->dev, "successfully removed."); + return 0; +} + +static const struct i2c_device_id akm8963_id[] = { + {AKM8963_I2C_NAME, 0 }, + { } +}; +static struct of_device_id akm_match_table[] = { + { .compatible = "akm,ak8963", }, + { }, +}; + +static const struct dev_pm_ops akm8963_pm_ops = { + .suspend = akm8963_suspend, + .resume = akm8963_resume, +}; + +//[ECID 000000] yangze add for ic information add 20121121 begin +static ssize_t akm_info_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "0x%x\n", chipid); +} + +static struct proc_dir_entry *akm_info_proc_file; +static int __init create_akm_info_proc_file(void) +{ + if(0xff == chipid) { + printk("not create akm8963 proc file due to unconnected\n"); + return 0; + } + akm_info_proc_file = create_proc_entry("driver/compass", 0644, NULL); + //printk("goes to create_acc_info_proc_file\n"); + if (akm_info_proc_file) { + akm_info_proc_file->read_proc = akm_info_read_proc; + } else{ + printk(KERN_INFO "proc file create failed!\n"); + } + return 0; +} + +//[ECID 000000] yangze add for ic information add 20121121 end + +static struct i2c_driver akm8963_driver = { + .probe = akm8963_probe, + .remove = akm8963_remove, + .id_table = akm8963_id, + .driver = { + .name = AKM8963_I2C_NAME, + .pm = &akm8963_pm_ops, + .of_match_table = akm_match_table, + }, +}; + +late_initcall(create_akm_info_proc_file); +module_i2c_driver(akm8963_driver); + + +MODULE_AUTHOR("viral wang "); +MODULE_DESCRIPTION("AKM8963 compass driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/zte-sensor/bma2xx.c b/drivers/misc/zte-sensor/bma2xx.c new file mode 100644 index 000000000000..a5a30f41647d --- /dev/null +++ b/drivers/misc/zte-sensor/bma2xx.c @@ -0,0 +1,3486 @@ +/* Date: 2011/7/4 17:00:00 + * Revision: 2.7 + */ + +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2011 Bosch Sensortec GmbH + * All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include + +#define BMA2XX_SW_CALIBRATION 1 +//#define BMA2XXX_ENABLE_INT1 //guliangzeng mask for INT 20131115 + +#define BMA2XXX_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + +#define BMA2XXX_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | ((val<> 6; + + return comres; +} + +static int bma2xx_set_range(struct i2c_client *client, unsigned char Range) +{ + int comres = 0; + unsigned char data1; + + if (Range < 4) { + comres = bma2xx_smbus_read_byte(client, + BMA2XXX_RANGE_SEL_REG, &data1); + switch (Range) { + case 0: + data1 = + BMA2XXX_SET_BITSLICE(data1, BMA2XXX_RANGE_SEL, 0); + break; + case 1: + data1 = + BMA2XXX_SET_BITSLICE(data1, BMA2XXX_RANGE_SEL, 5); + break; + case 2: + data1 = + BMA2XXX_SET_BITSLICE(data1, BMA2XXX_RANGE_SEL, 8); + break; + case 3: + data1 = BMA2XXX_SET_BITSLICE(data1, + BMA2XXX_RANGE_SEL, 12); + break; + default: + break; + } + comres += bma2xx_smbus_write_byte(client, + BMA2XXX_RANGE_SEL_REG, + &data1); + } else { + comres = -1; + } + + return comres; +} + +static int bma2xx_get_range(struct i2c_client *client, unsigned char *Range) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_RANGE_SEL__REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_RANGE_SEL); + *Range = data; + + return comres; +} + +static int bma2xx_set_bandwidth(struct i2c_client *client, unsigned char BW) +{ + int comres = 0; + unsigned char data; + int Bandwidth = 0; + + if (BW < 8) { + switch (BW) { + case 0: + Bandwidth = BMA2XXX_BW_7_81HZ; + break; + case 1: + Bandwidth = BMA2XXX_BW_15_63HZ; + break; + case 2: + Bandwidth = BMA2XXX_BW_31_25HZ; + break; + case 3: + Bandwidth = BMA2XXX_BW_62_50HZ; + break; + case 4: + Bandwidth = BMA2XXX_BW_125HZ; + break; + case 5: + Bandwidth = BMA2XXX_BW_250HZ; + break; + case 6: + Bandwidth = BMA2XXX_BW_500HZ; + break; + case 7: + Bandwidth = BMA2XXX_BW_1000HZ; + break; + default: + break; + } + comres = bma2xx_smbus_read_byte(client, + BMA2XXX_BANDWIDTH__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_BANDWIDTH, Bandwidth); + comres += bma2xx_smbus_write_byte(client, + BMA2XXX_BANDWIDTH__REG, + &data); + } else { + comres = -1; + } + + return comres; +} + +static int bma2xx_get_bandwidth(struct i2c_client *client, unsigned char *BW) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_BANDWIDTH__REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_BANDWIDTH); + if (data <= 8) { + *BW = 0; + } else { + if (data >= 0x0F) + *BW = 7; + else + *BW = data - 8; + + } + + return comres; +} + +#ifdef CONFIG_OF +static int bma2xx_power_init(struct bma2xx_data *data, bool on) +{ + int rc; + int vol_uv; + int enabled = 0; + + if (!on) { + if (data->vdd_enabled) { + regulator_disable(data->vdd); + data->vdd_enabled = false; + } + if (data->vio_enabled) { + regulator_disable(data->vio); + data->vio_enabled = false; + } + + regulator_set_voltage(data->vdd, 0, BMA2XX_VDD_MAX_UV); + regulator_set_voltage(data->vio, 0, BMA2XX_VIO_MAX_UV); + } else { + if (!(data->vdd)){ + data->vdd = regulator_get(&data->bma2xx_client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->bma2xx_client->dev, "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + } + vol_uv = regulator_get_voltage(data->vdd); + enabled = regulator_is_enabled(data->vdd); + dev_info(&data->bma2xx_client->dev, "vdd current voltate is %duv, enabled = %d ", vol_uv, enabled); + if (((vol_uv <= BMA2XX_VDD_MIN_UV) || (vol_uv >= BMA2XX_VDD_MAX_UV)) + && (regulator_count_voltages(data->vdd) > 0)) { + rc = regulator_set_voltage(data->vdd, BMA2XX_VDD_MIN_UV, + BMA2XX_VDD_MAX_UV); + if (rc) { + dev_err(&data->bma2xx_client->dev, + "Regulator set failed vdd rc=%d\n", + rc); + goto reg_vdd_put; + } + } + if (enabled != 1) { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->bma2xx_client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + goto reg_vdd_put; + } + data->vdd_enabled = true; + } + + if (!(data->vio)){ + data->vio = regulator_get(&data->bma2xx_client->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->bma2xx_client->dev, + "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_dis; + + } + } + + vol_uv = regulator_get_voltage(data->vio); + enabled = regulator_is_enabled(data->vio); + dev_info(&data->bma2xx_client->dev, "vio current voltate is %duv, enabled = %d \n", vol_uv, enabled); + if (((vol_uv <= BMA2XX_VIO_MIN_UV) || (vol_uv >= BMA2XX_VIO_MAX_UV)) + && (regulator_count_voltages(data->vio) > 0)) { + rc = regulator_set_voltage(data->vio, BMA2XX_VIO_MIN_UV, + BMA2XX_VIO_MAX_UV); + if (rc) { + dev_err(&data->bma2xx_client->dev, + "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + if (enabled != 1) { + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->bma2xx_client->dev, + "Regulator vio enable failed rc=%d\n", rc); + goto reg_vio_put; + } + data->vio_enabled = true; + msleep(10); + } + } + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_dis: + if (data->vdd_enabled){ + regulator_disable(data->vdd); + data->vdd_enabled = false; + } +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} +#else +static int bma2xx_power_init(struct bma2xx_data *data, bool on) +{ + return 0; +} + +#endif + +#if defined(BMA2XXX_ENABLE_INT1) || defined(BMA2XXX_ENABLE_INT2) +static int bma2xx_get_interruptstatus1(struct i2c_client *client, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_STATUS1_REG, &data); + *intstatus = data; + + return comres; +} + +static int bma2xx_get_HIGH_first(struct i2c_client *client, unsigned char param, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + switch (param) { + case 0: + comres = + bma2xx_smbus_read_byte(client, + BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_FIRST_X); + *intstatus = data; + break; + case 1: + comres = + bma2xx_smbus_read_byte(client, + BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = + bma2xx_smbus_read_byte(client, + BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int bma2xx_get_HIGH_sign(struct i2c_client *client, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_SIGN_S); + *intstatus = data; + + return comres; +} + +static int bma2xx_get_slope_first(struct i2c_client *client, + unsigned char param, unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + switch (param) { + case 0: + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_TAP_SLOPE_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_FIRST_X); + *intstatus = data; + break; + case 1: + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_TAP_SLOPE_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_TAP_SLOPE_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int bma2xx_get_slope_sign(struct i2c_client *client, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_TAP_SLOPE_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_SIGN_S); + *intstatus = data; + + return comres; +} + +static int bma2xx_get_orient_status(struct i2c_client *client, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_ORIENT_S); + *intstatus = data; + + return comres; +} + +static int bma2xx_get_orient_flat_status(struct i2c_client *client, + unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_FLAT_S); + *intstatus = data; + + return comres; +} +#endif /* defined(BMA2XXX_ENABLE_INT1)||defined(BMA2XXX_ENABLE_INT2) */ +static int bma2xx_set_Int_Mode(struct i2c_client *client, unsigned char Mode) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, + BMA2XXX_INT_MODE_SEL__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_INT_MODE_SEL, Mode); + comres = bma2xx_smbus_write_byte(client, + BMA2XXX_INT_MODE_SEL__REG, &data); + + return comres; +} + +static int bma2xx_get_Int_Mode(struct i2c_client *client, unsigned char *Mode) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, + BMA2XXX_INT_MODE_SEL__REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_INT_MODE_SEL); + *Mode = data; + + return comres; +} +static int bma2xx_set_slope_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_SLOPE_DUR__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_SLOPE_DUR, duration); + comres = bma2xx_smbus_write_byte(client, BMA2XXX_SLOPE_DUR__REG, &data); + + return comres; +} + +static int bma2xx_get_slope_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_SLOPE_DURN_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_DUR); + *status = data; + + return comres; +} + +static int bma2xx_set_slope_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_SLOPE_THRES__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_SLOPE_THRES, threshold); + comres = bma2xx_smbus_write_byte(client, + BMA2XXX_SLOPE_THRES__REG, &data); + + return comres; +} + +static int bma2xx_get_slope_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_SLOPE_THRES_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_SLOPE_THRES); + *status = data; + + return comres; +} +static int bma2xx_set_low_g_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_LOWG_DUR__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_LOWG_DUR, duration); + comres = bma2xx_smbus_write_byte(client, BMA2XXX_LOWG_DUR__REG, &data); + + return comres; +} + +static int bma2xx_get_low_g_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_LOW_DURN_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_LOWG_DUR); + *status = data; + + return comres; +} + +static int bma2xx_set_low_g_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_LOWG_THRES__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_LOWG_THRES, threshold); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_LOWG_THRES__REG, &data); + + return comres; +} + +static int bma2xx_get_low_g_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_LOW_THRES_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_LOWG_THRES); + *status = data; + + return comres; +} + +static int bma2xx_set_high_g_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_HIGHG_DUR__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_HIGHG_DUR, duration); + comres = bma2xx_smbus_write_byte(client, BMA2XXX_HIGHG_DUR__REG, &data); + + return comres; +} + +static int bma2xx_get_high_g_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_HIGH_DURN_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_DUR); + *status = data; + + return comres; +} + +static int bma2xx_set_high_g_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_HIGHG_THRES__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_HIGHG_THRES, threshold); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_HIGHG_THRES__REG, &data); + + return comres; +} + +static int bma2xx_get_high_g_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_HIGH_THRES_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_HIGHG_THRES); + *status = data; + + return comres; +} + +static int bma2xx_set_tap_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_DUR__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_TAP_DUR, duration); + comres = bma2xx_smbus_write_byte(client, BMA2XXX_TAP_DUR__REG, &data); + + return comres; +} + +static int bma2xx_get_tap_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_TAP_DUR); + *status = data; + + return comres; +} + +static int bma2xx_set_tap_shock(struct i2c_client *client, unsigned char setval) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_TAP_SHOCK_DURN__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_TAP_SHOCK_DURN, setval); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_TAP_SHOCK_DURN__REG, &data); + + return comres; +} + +static int bma2xx_get_tap_shock(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_TAP_SHOCK_DURN); + *status = data; + + return comres; +} + +static int bma2xx_set_tap_quiet(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_TAP_QUIET_DURN__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_TAP_QUIET_DURN, duration); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_TAP_QUIET_DURN__REG, &data); + + return comres; +} + +static int bma2xx_get_tap_quiet(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_TAP_QUIET_DURN); + *status = data; + + return comres; +} + +static int bma2xx_set_tap_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_THRES__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_TAP_THRES, threshold); + comres = bma2xx_smbus_write_byte(client, BMA2XXX_TAP_THRES__REG, &data); + + return comres; +} + +static int bma2xx_get_tap_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_THRES_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_TAP_THRES); + *status = data; + + return comres; +} + +static int bma2xx_set_tap_samp(struct i2c_client *client, unsigned char samp) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_TAP_SAMPLES__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_TAP_SAMPLES, samp); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_TAP_SAMPLES__REG, &data); + + return comres; +} + +static int bma2xx_get_tap_samp(struct i2c_client *client, unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_TAP_THRES_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_TAP_SAMPLES); + *status = data; + + return comres; +} + +static int bma2xx_set_orient_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_MODE__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_ORIENT_MODE, mode); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_ORIENT_MODE__REG, &data); + + return comres; +} + +static int bma2xx_get_orient_mode(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_ORIENT_MODE); + *status = data; + + return comres; +} + +static int bma2xx_set_orient_blocking(struct i2c_client *client, + unsigned char samp) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_BLOCK__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_ORIENT_BLOCK, samp); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_ORIENT_BLOCK__REG, &data); + + return comres; +} + +static int bma2xx_get_orient_blocking(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_ORIENT_BLOCK); + *status = data; + + return comres; +} + +static int bma2xx_set_orient_hyst(struct i2c_client *client, + unsigned char orienthyst) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_HYST__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_ORIENT_HYST, orienthyst); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_ORIENT_HYST__REG, &data); + + return comres; +} + +static int bma2xx_get_orient_hyst(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_ORIENT_PARAM_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_ORIENT_HYST); + *status = data; + + return comres; +} +static int bma2xx_set_theta_blocking(struct i2c_client *client, + unsigned char thetablk) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_THETA_BLOCK__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_THETA_BLOCK, thetablk); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_THETA_BLOCK__REG, &data); + + return comres; +} + +static int bma2xx_get_theta_blocking(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_THETA_BLOCK_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_THETA_BLOCK); + *status = data; + + return comres; +} + +static int bma2xx_set_theta_flat(struct i2c_client *client, + unsigned char thetaflat) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_THETA_FLAT__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_THETA_FLAT, thetaflat); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_THETA_FLAT__REG, &data); + + return comres; +} + +static int bma2xx_get_theta_flat(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_THETA_FLAT_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_THETA_FLAT); + *status = data; + + return comres; +} + +static int bma2xx_set_flat_hold_time(struct i2c_client *client, + unsigned char holdtime) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_FLAT_HOLD_TIME__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_FLAT_HOLD_TIME, holdtime); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_FLAT_HOLD_TIME__REG, &data); + + return comres; +} + +static int bma2xx_get_flat_hold_time(struct i2c_client *client, + unsigned char *holdtime) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_FLAT_HOLD_TIME_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_FLAT_HOLD_TIME); + *holdtime = data; + + return comres; +} + +static int bma2xx_write_reg(struct i2c_client *client, unsigned char addr, + unsigned char *data) +{ + int comres = 0; + comres = bma2xx_smbus_write_byte(client, addr, data); + + return comres; +} + +static int bma2xx_set_offset_target_x(struct i2c_client *client, + unsigned char offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_COMP_TARGET_OFFSET_X__REG, + &data); + data = + BMA2XXX_SET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_X, + offsettarget); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_COMP_TARGET_OFFSET_X__REG, + &data); + + return comres; +} + +static int bma2xx_get_offset_target_x(struct i2c_client *client, + unsigned char *offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_OFFSET_PARAMS_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_X); + *offsettarget = data; + + return comres; +} + +static int bma2xx_set_offset_target_y(struct i2c_client *client, + unsigned char offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_COMP_TARGET_OFFSET_Y__REG, + &data); + data = + BMA2XXX_SET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_Y, + offsettarget); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_COMP_TARGET_OFFSET_Y__REG, + &data); + + return comres; +} + +static int bma2xx_get_offset_target_y(struct i2c_client *client, + unsigned char *offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_OFFSET_PARAMS_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_Y); + *offsettarget = data; + + return comres; +} + +static int bma2xx_set_offset_target_z(struct i2c_client *client, + unsigned char offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_COMP_TARGET_OFFSET_Z__REG, + &data); + data = + BMA2XXX_SET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_Z, + offsettarget); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_COMP_TARGET_OFFSET_Z__REG, + &data); + + return comres; +} + +static int bma2xx_get_offset_target_z(struct i2c_client *client, + unsigned char *offsettarget) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_OFFSET_PARAMS_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_COMP_TARGET_OFFSET_Z); + *offsettarget = data; + + return comres; +} + +static int bma2xx_get_cal_ready(struct i2c_client *client, + unsigned char *calrdy) +{ + int comres = 0; + unsigned char data; + + comres = bma2xx_smbus_read_byte(client, BMA2XXX_OFFSET_CTRL_REG, &data); + data = BMA2XXX_GET_BITSLICE(data, BMA2XXX_FAST_COMP_RDY_S); + *calrdy = data; + + return comres; +} + +static int bma2xx_set_cal_trigger(struct i2c_client *client, + unsigned char caltrigger) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_EN_FAST_COMP__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_EN_FAST_COMP, caltrigger); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_EN_FAST_COMP__REG, &data); + + return comres; +} + +static int bma2xx_set_selftest_st(struct i2c_client *client, + unsigned char selftest) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_EN_SELF_TEST__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_EN_SELF_TEST, selftest); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_EN_SELF_TEST__REG, &data); + + return comres; +} + +static int bma2xx_set_selftest_stn(struct i2c_client *client, unsigned char stn) +{ + int comres = 0; + unsigned char data; + + comres = + bma2xx_smbus_read_byte(client, BMA2XXX_NEG_SELF_TEST__REG, &data); + data = BMA2XXX_SET_BITSLICE(data, BMA2XXX_NEG_SELF_TEST, stn); + comres = + bma2xx_smbus_write_byte(client, BMA2XXX_NEG_SELF_TEST__REG, &data); + + return comres; +} +static int bma2xx_read_accel_x(struct i2c_client *client, short *a_x) +{ + int comres; + unsigned char data[2]; + + comres = + bma2xx_smbus_read_byte_block(client, BMA2XXX_ACC_X_LSB__REG, data, + 2); + *a_x = + BMA2XXX_GET_BITSLICE(data[0], + BMA2XXX_ACC_X_LSB) | + (BMA2XXX_GET_BITSLICE(data[1], BMA2XXX_ACC_X_MSB) << + BMA2XXX_ACC_X_LSB__LEN); + *a_x = + *a_x << (sizeof(short) * 8 - + (BMA2XXX_ACC_X_LSB__LEN + BMA2XXX_ACC_X_MSB__LEN)); + *a_x = + *a_x >> (sizeof(short) * 8 - + (BMA2XXX_ACC_X_LSB__LEN + BMA2XXX_ACC_X_MSB__LEN)); + + return comres; +} +static int bma2xx_read_accel_y(struct i2c_client *client, short *a_y) +{ + int comres; + unsigned char data[2]; + + comres = + bma2xx_smbus_read_byte_block(client, BMA2XXX_ACC_Y_LSB__REG, data, + 2); + *a_y = + BMA2XXX_GET_BITSLICE(data[0], + BMA2XXX_ACC_Y_LSB) | + (BMA2XXX_GET_BITSLICE(data[1], BMA2XXX_ACC_Y_MSB) << + BMA2XXX_ACC_Y_LSB__LEN); + *a_y = + *a_y << (sizeof(short) * 8 - + (BMA2XXX_ACC_Y_LSB__LEN + BMA2XXX_ACC_Y_MSB__LEN)); + *a_y = + *a_y >> (sizeof(short) * 8 - + (BMA2XXX_ACC_Y_LSB__LEN + BMA2XXX_ACC_Y_MSB__LEN)); + + return comres; +} + +static int bma2xx_read_accel_z(struct i2c_client *client, short *a_z) +{ + int comres; + unsigned char data[2]; + + comres = + bma2xx_smbus_read_byte_block(client, BMA2XXX_ACC_Z_LSB__REG, data, + 2); + *a_z = + BMA2XXX_GET_BITSLICE(data[0], + BMA2XXX_ACC_Z_LSB) | + BMA2XXX_GET_BITSLICE(data[1], BMA2XXX_ACC_Z_MSB) + << BMA2XXX_ACC_Z_LSB__LEN; + *a_z = + *a_z << (sizeof(short) * 8 - + (BMA2XXX_ACC_Z_LSB__LEN + BMA2XXX_ACC_Z_MSB__LEN)); + *a_z = + *a_z >> (sizeof(short) * 8 - + (BMA2XXX_ACC_Z_LSB__LEN + BMA2XXX_ACC_Z_MSB__LEN)); + + return comres; +} + +static int bma2xx_read_accel_xyz(struct i2c_client *client, + struct bma2xxacc *acc) +{ + int comres; + unsigned char data[6]; + + comres = bma2xx_smbus_read_byte_block(client, + BMA2XXX_ACC_X_LSB__REG, data, 6); + + acc->x = BMA2XXX_GET_BITSLICE(data[0], BMA2XXX_ACC_X_LSB) + | (BMA2XXX_GET_BITSLICE(data[1], + BMA2XXX_ACC_X_MSB) << + BMA2XXX_ACC_X_LSB__LEN); + acc->x = + acc->x << (sizeof(short) * 8 - + (BMA2XXX_ACC_X_LSB__LEN + BMA2XXX_ACC_X_MSB__LEN)); + acc->x = + acc->x >> (sizeof(short) * 8 - + (BMA2XXX_ACC_X_LSB__LEN + BMA2XXX_ACC_X_MSB__LEN)); + acc->y = BMA2XXX_GET_BITSLICE(data[2], BMA2XXX_ACC_Y_LSB) + | (BMA2XXX_GET_BITSLICE(data[3], + BMA2XXX_ACC_Y_MSB) << + BMA2XXX_ACC_Y_LSB__LEN); + acc->y = + acc->y << (sizeof(short) * 8 - + (BMA2XXX_ACC_Y_LSB__LEN + BMA2XXX_ACC_Y_MSB__LEN)); + acc->y = + acc->y >> (sizeof(short) * 8 - + (BMA2XXX_ACC_Y_LSB__LEN + BMA2XXX_ACC_Y_MSB__LEN)); + + acc->z = BMA2XXX_GET_BITSLICE(data[4], BMA2XXX_ACC_Z_LSB) + | (BMA2XXX_GET_BITSLICE(data[5], + BMA2XXX_ACC_Z_MSB) << + BMA2XXX_ACC_Z_LSB__LEN); + acc->z = + acc->z << (sizeof(short) * 8 - + (BMA2XXX_ACC_Z_LSB__LEN + BMA2XXX_ACC_Z_MSB__LEN)); + acc->z = + acc->z >> (sizeof(short) * 8 - + (BMA2XXX_ACC_Z_LSB__LEN + BMA2XXX_ACC_Z_MSB__LEN)); + + return comres; +} + +static void bma2xx_work_func(struct work_struct *work) +{ + struct bma2xx_data *bma2xx = container_of((struct delayed_work *)work, + struct bma2xx_data, work); + static struct bma2xxacc acc; + int X, Y, Z; + unsigned long delay = msecs_to_jiffies(atomic_read(&bma2xx->delay)); + X = 0; + Y = 0; + Z = 0; + bma2xx_read_accel_xyz(bma2xx->bma2xx_client, &acc); + switch (bma2xx->orientation) { + case BMA_ORI_100_010_001: + X = acc.x; + Y = acc.y; + Z = acc.z; + break; + case BMA_ORI_010_100_001: + X = acc.y; + Y = acc.x; + Z = acc.z; + break; + case BMA_ORI_f00_010_001: + X = -acc.x; + Y = acc.y; + Z = acc.z; + break; + case BMA_ORI_f00_0f0_001: + X = -acc.x; + Y = -acc.y; + Z = acc.z; + break; + case BMA_ORI_100_0f0_001: + X = acc.x; + Y = -acc.y; + Z = acc.z; + break; + case BMA_ORI_100_010_00f: + X = acc.x; + Y = acc.y; + Z = -acc.z; + break; + case BMA_ORI_010_100_00f: + X = acc.y; + Y = acc.x; + Z = -acc.z; + break; + case BMA_ORI_f00_010_00f: + X = -acc.x; + Y = acc.y; + Z = -acc.z; + break; + case BMA_ORI_f00_0f0_00f: + X = -acc.x; + Y = -acc.y; + Z = -acc.z; + break; + case BMA_ORI_100_0f0_00f: + X = acc.x; + Y = -acc.y; + Z = -acc.z; + break; + case BMA_ORI_010_f00_00f: + X = acc.y; + Y = -acc.x; + Z = -acc.z; + break; + case BMA_ORI_0f0_100_00f: + X = -acc.y; + Y = acc.x; + Z = -acc.z; + break; + case BMA_ORI_0f0_100_001: + X = -acc.y; + Y = acc.x; + Z = acc.z; + break; + default: + break; + } + + //for 2g range convert + X = X * 1024 / 256; + Y = Y * 1024 / 256; + Z = Z * 1024 / 256; +#ifdef BMA2XX_SW_CALIBRATION + input_report_abs(bma2xx->input, ABS_X, X-bma2xx_offset[0]); + input_report_abs(bma2xx->input, ABS_Y, Y-bma2xx_offset[1]); + input_report_abs(bma2xx->input, ABS_Z, Z-bma2xx_offset[2]); +#else + + input_report_abs(bma2xx->input, ABS_X, X); + input_report_abs(bma2xx->input, ABS_Y, Y); + input_report_abs(bma2xx->input, ABS_Z, Z); +#endif + input_sync(bma2xx->input); + mutex_lock(&bma2xx->value_mutex); + bma2xx->value = acc; + mutex_unlock(&bma2xx->value_mutex); + schedule_delayed_work(&bma2xx->work, delay); +} + +static ssize_t bma2xx_register_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int address, value; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + sscanf(buf, "%d%d", &address, &value); + + if (bma2xx_write_reg + (bma2xx->bma2xx_client, (unsigned char)address, + (unsigned char *)&value) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_register_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + size_t count = 0; + u8 reg[0x3d]; + int i; + + for (i = 0; i < 0x3d; i++) { + bma2xx_smbus_read_byte(bma2xx->bma2xx_client, i, reg + i); + + count += sprintf(&buf[count], "0x%x: %d\n", i, reg[i]); + } + return count; + +} +static ssize_t bma2xx_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_range(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2xx_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_range(bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_bandwidth_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_bandwidth(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_bandwidth_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_bandwidth(bma2xx->bma2xx_client, + (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_mode(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2xx_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_mode(bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bma2xx_data *bma2xx = input_get_drvdata(input); + struct bma2xxacc acc_value; + + mutex_lock(&bma2xx->value_mutex); + acc_value = bma2xx->value; + mutex_unlock(&bma2xx->value_mutex); + + return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y, + acc_value.z); +} + +static ssize_t bma2xx_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2xx->delay)); + +} + +static ssize_t bma2xx_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (data > BMA2XXX_MAX_DELAY) + data = BMA2XXX_MAX_DELAY; + atomic_set(&bma2xx->delay, (unsigned int)data); + dev_info(&client->dev, "set delay to %ldms\n", data); + return count; +} + +static ssize_t bma2xx_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2xx->enable)); + +} + +static void bma2xx_set_enable(struct device *dev, int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + int pre_enable = atomic_read(&bma2xx->enable); + dev_info(&client->dev, "set enable from %d to %d\n", pre_enable, enable); + + mutex_lock(&bma2xx->enable_mutex); + if (enable) { + if (pre_enable == 0) { + bma2xx_power_init(bma2xx, true); + bma2xx_set_bandwidth(client, BMA2XXX_BW_SET); + bma2xx_set_range(client, BMA2XXX_RANGE_SET); + bma2xx_set_mode(bma2xx->bma2xx_client, + BMA2XXX_MODE_NORMAL); + schedule_delayed_work(&bma2xx->work, + msecs_to_jiffies(atomic_read + (&bma2xx-> + delay))); + atomic_set(&bma2xx->enable, 1); + } + + } else { + if (pre_enable == 1) { + bma2xx_set_mode(bma2xx->bma2xx_client, + BMA2XXX_MODE_SUSPEND); + cancel_delayed_work_sync(&bma2xx->work); + atomic_set(&bma2xx->enable, 0); + bma2xx_power_init(bma2xx, false); + } + } + mutex_unlock(&bma2xx->enable_mutex); + +} + +static ssize_t bma2xx_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if ((data == 0) || (data == 1)) + bma2xx_set_enable(dev, data); + + return count; +} + +static ssize_t bma2xx_enable_int_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int type, value; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + sscanf(buf, "%d%d", &type, &value); + + if (bma2xx_set_Int_Enable(bma2xx->bma2xx_client, type, value) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_int_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_Int_Mode(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2xx_int_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); +/*guliangzeng modify for compile error 201131114 start*/ + int error; + //data = kstrtoul(buf, NULL, 10); + error = kstrtoul(buf, 10, &data); + if (error) + return error; +/*guliangzeng modify for compile error 201131114 end*/ + if (bma2xx_set_Int_Mode(bma2xx->bma2xx_client, data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_slope_duration_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_slope_duration(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_slope_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_slope_duration + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_slope_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_slope_threshold(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_slope_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_slope_threshold + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_high_g_duration_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_high_g_duration(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_high_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_high_g_duration + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_high_g_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_high_g_threshold(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_high_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_high_g_threshold + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_low_g_duration_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_low_g_duration(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_low_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_low_g_duration + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_low_g_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_low_g_threshold(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_low_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_low_g_threshold + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_tap_threshold_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_tap_threshold(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_tap_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (bma2xx_set_tap_threshold(bma2xx->bma2xx_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_tap_duration_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_tap_duration(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_tap_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_tap_duration(bma2xx->bma2xx_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_tap_quiet_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_tap_quiet(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_tap_quiet_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_tap_quiet(bma2xx->bma2xx_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_tap_shock_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_tap_shock(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_tap_shock_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_tap_shock(bma2xx->bma2xx_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_tap_samp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_tap_samp(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_tap_samp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_tap_samp(bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_orient_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_orient_mode(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_orient_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_orient_mode(bma2xx->bma2xx_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_orient_blocking_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_orient_blocking(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_orient_blocking_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_orient_blocking + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_orient_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_orient_hyst(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_orient_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_orient_hyst(bma2xx->bma2xx_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_orient_theta_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_theta_blocking(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_orient_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_theta_blocking + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_flat_theta_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_theta_flat(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_flat_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_theta_flat(bma2xx->bma2xx_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} +static ssize_t bma2xx_flat_hold_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_flat_hold_time(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_flat_hold_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_flat_hold_time + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2xx_fast_calibration_x_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_offset_target_x(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_fast_calibration_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_offset_target_x + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + if (bma2xx_set_cal_trigger(bma2xx->bma2xx_client, 1) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2xx_get_cal_ready(bma2xx->bma2xx_client, &tmp); + + printk(KERN_INFO "wait 2ms and got cal ready flag is %d\n", + tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "x axis fast calibration finished\n"); + return count; +} + +static ssize_t bma2xx_fast_calibration_y_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_offset_target_y(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_fast_calibration_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_offset_target_y + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + if (bma2xx_set_cal_trigger(bma2xx->bma2xx_client, 2) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2xx_get_cal_ready(bma2xx->bma2xx_client, &tmp); + + printk(KERN_INFO "wait 2ms and got cal ready flag is %d\n", + tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "y axis fast calibration finished\n"); + return count; +} + +static ssize_t bma2xx_fast_calibration_z_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + if (bma2xx_get_offset_target_z(bma2xx->bma2xx_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2xx_fast_calibration_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (bma2xx_set_offset_target_z + (bma2xx->bma2xx_client, (unsigned char)data) < 0) + return -EINVAL; + + if (bma2xx_set_cal_trigger(bma2xx->bma2xx_client, 3) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2xx_get_cal_ready(bma2xx->bma2xx_client, &tmp); + + printk(KERN_INFO "wait 2ms and got cal ready flag is %d\n", + tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "z axis fast calibration finished\n"); + return count; +} + +static ssize_t bma2xx_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2xx->selftest_result)); + +} + +static ssize_t bma2xx_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + unsigned long data; + unsigned char clear_value = 0; + int error; + short value1 = 0; + short value2 = 0; + short diff = 0; + unsigned long result = 0; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *bma2xx = i2c_get_clientdata(client); + + error = kstrtoul(buf, 10, &data); + if (error) + return error; + + if (data != 1) + return -EINVAL; + /* set to 2 G range */ + if (bma2xx_set_range(bma2xx->bma2xx_client, 0) < 0) + return -EINVAL; + + bma2xx_write_reg(bma2xx->bma2xx_client, 0x32, &clear_value); + + bma2xx_set_selftest_st(bma2xx->bma2xx_client, 1); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 0); + mdelay(10); + bma2xx_read_accel_x(bma2xx->bma2xx_client, &value1); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 1); + mdelay(10); + bma2xx_read_accel_x(bma2xx->bma2xx_client, &value2); + diff = value1 - value2; + + printk(KERN_INFO "diff x is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + + if (abs(diff) < 204) + result |= 1; + + bma2xx_set_selftest_st(bma2xx->bma2xx_client, 2); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 0); + mdelay(10); + bma2xx_read_accel_y(bma2xx->bma2xx_client, &value1); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 1); + mdelay(10); + bma2xx_read_accel_y(bma2xx->bma2xx_client, &value2); + diff = value1 - value2; + printk(KERN_INFO "diff y is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + if (abs(diff) < 204) + result |= 2; + + bma2xx_set_selftest_st(bma2xx->bma2xx_client, 3); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 0); + mdelay(10); + bma2xx_read_accel_z(bma2xx->bma2xx_client, &value1); + bma2xx_set_selftest_stn(bma2xx->bma2xx_client, 1); + mdelay(10); + bma2xx_read_accel_z(bma2xx->bma2xx_client, &value2); + diff = value1 - value2; + + printk(KERN_INFO "diff z is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + if (abs(diff) < 102) + result |= 4; + + atomic_set(&bma2xx->selftest_result, (unsigned int)result); + + printk(KERN_INFO "self test finished\n"); + + return count; +} +#ifdef BMA2XX_SW_CALIBRATION +static ssize_t bma2xx_get_offset(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d, %d, %d\n", bma2xx_offset[0], + bma2xx_offset[1], bma2xx_offset[2]); +} + +static ssize_t bma2xx_set_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int x, y, z; + int err = -EINVAL; + struct i2c_client *client = to_i2c_client(dev); + struct bma2xx_data *dd = i2c_get_clientdata(client); + /*guliangzeng modify for compile error 201131114 start*/ + //struct input_dev *input_dev = dd->input; + /*guliangzeng modify for compile error 201131114 end*/ + + err = sscanf(buf, "%d %d %d", &x, &y, &z); + if (err != 3) { + pr_err("invalid parameter number: %d\n", err); + return err; + } + mutex_lock(&dd->value_mutex); + bma2xx_offset[0] = x; + bma2xx_offset[1] = y; + bma2xx_offset[2] = z; + mutex_unlock(&dd->value_mutex); + return count; +} +/* jinfeichao modified for CTS start */ +static DEVICE_ATTR(offset, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_get_offset, bma2xx_set_offset); +#endif + +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_range_show, bma2xx_range_store); +static DEVICE_ATTR(bandwidth, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_bandwidth_show, bma2xx_bandwidth_store); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_mode_show, bma2xx_mode_store); +static DEVICE_ATTR(value, S_IRUGO, bma2xx_value_show, NULL); +static DEVICE_ATTR(pollrate_ms, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_delay_show, bma2xx_delay_store); +static DEVICE_ATTR(enable_device, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_enable_show, bma2xx_enable_store); +static DEVICE_ATTR(enable_int, S_IWUSR | S_IWGRP, + NULL, bma2xx_enable_int_store); +static DEVICE_ATTR(int_mode, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_int_mode_show, bma2xx_int_mode_store); +static DEVICE_ATTR(slope_duration, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_slope_duration_show, bma2xx_slope_duration_store); +static DEVICE_ATTR(slope_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_slope_threshold_show, bma2xx_slope_threshold_store); +static DEVICE_ATTR(high_g_duration, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_high_g_duration_show, bma2xx_high_g_duration_store); +static DEVICE_ATTR(high_g_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_high_g_threshold_show, bma2xx_high_g_threshold_store); +static DEVICE_ATTR(low_g_duration, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_low_g_duration_show, bma2xx_low_g_duration_store); +static DEVICE_ATTR(low_g_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_low_g_threshold_show, bma2xx_low_g_threshold_store); +static DEVICE_ATTR(tap_duration, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_tap_duration_show, bma2xx_tap_duration_store); +static DEVICE_ATTR(tap_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_tap_threshold_show, bma2xx_tap_threshold_store); +static DEVICE_ATTR(tap_quiet, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_tap_quiet_show, bma2xx_tap_quiet_store); +static DEVICE_ATTR(tap_shock, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_tap_shock_show, bma2xx_tap_shock_store); +static DEVICE_ATTR(tap_samp, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_tap_samp_show, bma2xx_tap_samp_store); +static DEVICE_ATTR(orient_mode, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_orient_mode_show, bma2xx_orient_mode_store); +static DEVICE_ATTR(orient_blocking, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_orient_blocking_show, bma2xx_orient_blocking_store); +static DEVICE_ATTR(orient_hyst, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_orient_hyst_show, bma2xx_orient_hyst_store); +static DEVICE_ATTR(orient_theta, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_orient_theta_show, bma2xx_orient_theta_store); +static DEVICE_ATTR(flat_theta, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_flat_theta_show, bma2xx_flat_theta_store); +static DEVICE_ATTR(flat_hold_time, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_flat_hold_time_show, bma2xx_flat_hold_time_store); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_register_show, bma2xx_register_store); +static DEVICE_ATTR(fast_calibration_x, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_fast_calibration_x_show, + bma2xx_fast_calibration_x_store); +static DEVICE_ATTR(fast_calibration_y, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_fast_calibration_y_show, + bma2xx_fast_calibration_y_store); +static DEVICE_ATTR(fast_calibration_z, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_fast_calibration_z_show, + bma2xx_fast_calibration_z_store); +static DEVICE_ATTR(selftest, S_IRUGO | S_IWUSR | S_IWGRP, + bma2xx_selftest_show, bma2xx_selftest_store); +/* jinfeichao modified for CTS end */ + +static struct attribute *bma2xx_attributes[] = { + &dev_attr_range.attr, + &dev_attr_bandwidth.attr, + &dev_attr_mode.attr, + &dev_attr_value.attr, + &dev_attr_pollrate_ms.attr, + &dev_attr_enable_device.attr, + &dev_attr_enable_int.attr, + &dev_attr_int_mode.attr, + &dev_attr_slope_duration.attr, + &dev_attr_slope_threshold.attr, + &dev_attr_high_g_duration.attr, + &dev_attr_high_g_threshold.attr, + &dev_attr_low_g_duration.attr, + &dev_attr_low_g_threshold.attr, + &dev_attr_tap_threshold.attr, + &dev_attr_tap_duration.attr, + &dev_attr_tap_quiet.attr, + &dev_attr_tap_shock.attr, + &dev_attr_tap_samp.attr, + &dev_attr_orient_mode.attr, + &dev_attr_orient_blocking.attr, + &dev_attr_orient_hyst.attr, + &dev_attr_orient_theta.attr, + &dev_attr_flat_theta.attr, + &dev_attr_flat_hold_time.attr, + &dev_attr_reg.attr, + &dev_attr_fast_calibration_x.attr, + &dev_attr_fast_calibration_y.attr, + &dev_attr_fast_calibration_z.attr, + &dev_attr_selftest.attr, +#ifdef BMA2XX_SW_CALIBRATION + &dev_attr_offset.attr, +#endif + NULL +}; + +static struct attribute_group bma2xx_attribute_group = { + .attrs = bma2xx_attributes +}; + +#if defined(BMA2XXX_ENABLE_INT1) || defined(BMA2XXX_ENABLE_INT2) +unsigned char *orient[] = { "upward looking portrait upright", + "upward looking portrait upside-down", + "upward looking landscape left", + "upward looking landscape right", + "downward looking portrait upright", + "downward looking portrait upside-down", + "downward looking landscape left", + "downward looking landscape right" +}; + +static void bma2xx_irq_work_func(struct work_struct *work) +{ + struct bma2xx_data *bma2xx = container_of((struct work_struct *)work, + struct bma2xx_data, irq_work); + + unsigned char status = 0; + unsigned char i; + unsigned char first_value = 0; + unsigned char sign_value = 0; + + bma2xx_get_interruptstatus1(bma2xx->bma2xx_client, &status); + + switch (status) { + + case 0x01: + pr_info("Low G interrupt happened\n"); + input_report_rel(bma2xx->input, LOW_G_INTERRUPT, + LOW_G_INTERRUPT_HAPPENED); + break; + case 0x02: + for (i = 0; i < 3; i++) { + bma2xx_get_HIGH_first(bma2xx->bma2xx_client, i, + &first_value); + if (first_value == 1) { + + bma2xx_get_HIGH_sign(bma2xx->bma2xx_client, + &sign_value); + + if (sign_value == 1) { + if (i == 0) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED); + if (i == 1) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED); + if (i == 2) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED); + } else { + if (i == 0) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X_HAPPENED); + if (i == 1) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y_HAPPENED); + if (i == 2) + input_report_rel(bma2xx->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z_HAPPENED); + + } + } + + } + break; + case 0x04: + for (i = 0; i < 3; i++) { + bma2xx_get_slope_first(bma2xx->bma2xx_client, i, + &first_value); + if (first_value == 1) { + + bma2xx_get_slope_sign(bma2xx->bma2xx_client, + &sign_value); + + if (sign_value == 1) { + if (i == 0) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED); + else if (i == 1) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED); + else if (i == 2) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED); + } else { + if (i == 0) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X_HAPPENED); + else if (i == 1) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y_HAPPENED); + else if (i == 2) + input_report_rel(bma2xx->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z_HAPPENED); + + } + } + + } + break; + + case 0x10: + input_report_rel(bma2xx->input, DOUBLE_TAP_INTERRUPT, + DOUBLE_TAP_INTERRUPT_HAPPENED); + break; + case 0x20: + input_report_rel(bma2xx->input, SINGLE_TAP_INTERRUPT, + SINGLE_TAP_INTERRUPT_HAPPENED); + break; + case 0x40: + bma2xx_get_orient_status(bma2xx->bma2xx_client, &first_value); + if (first_value == 0) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 1) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 2) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 3) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + else if (first_value == 4) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 5) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 6) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 7) + input_report_abs(bma2xx->input, ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + break; + case 0x80: + bma2xx_get_orient_flat_status(bma2xx->bma2xx_client, + &sign_value); + if (sign_value == 1) + input_report_abs(bma2xx->input, FLAT_INTERRUPT, + FLAT_INTERRUPT_TURE_HAPPENED); + else + input_report_abs(bma2xx->input, FLAT_INTERRUPT, + FLAT_INTERRUPT_FALSE_HAPPENED); + break; + default: + break; + } +} + +static irqreturn_t bma2xx_irq_handler(int irq, void *handle) +{ + + struct bma2xx_data *data = handle; + + if (data == NULL) + return IRQ_HANDLED; + if (data->bma2xx_client == NULL) + return IRQ_HANDLED; + + schedule_work(&data->irq_work); + + return IRQ_HANDLED; + +} +#endif /* defined(BMA2XXX_ENABLE_INT1)||defined(BMA2XXX_ENABLE_INT2) */ + +#ifdef CONFIG_OF +static int bma2xx_parse_gpio(struct i2c_client *client) +{ + struct device_node *np = client->dev.of_node; + u32 temp_val; + int rc; + + temp_val = of_get_named_gpio(np, "bma2xx,gpio-irq1", 0); + if (gpio_is_valid(temp_val)) { + rc = gpio_request(temp_val, "bma2xx_irq1"); + if (rc) { + dev_err(&client->dev, "irq1 gpio request failed"); + } else + gpio_direction_input(temp_val); + client->irq = temp_val; + } + + temp_val = of_get_named_gpio(np, "bma2xx,gpio-irq2", 0); + if (gpio_is_valid(temp_val)) { + rc = gpio_request(temp_val, "bma2xx_irq2"); + if (rc) { + dev_err(&client->dev, "irq2 gpio request failed"); + } else + gpio_direction_input(temp_val); + } + return 0; +} +#else +static int bma2xx_parse_gpio(struct i2c_client *client) +{ + return 0; +} +#endif + +static int bma2xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct bma2xx_data *data; + u32 val = 0; +#ifdef BMA2XX_SW_CALIBRATION + bma2xx_offset[0] = 0; + bma2xx_offset[1] = 0; + bma2xx_offset[2] = 0; +#endif + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "[bma2xxx]i2c_check_functionality error\n"); + goto exit; + } + + data = kzalloc(sizeof(struct bma2xx_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + i2c_set_clientdata(client, data); + data->bma2xx_client = client; + mutex_init(&data->value_mutex); + mutex_init(&data->mode_mutex); + mutex_init(&data->enable_mutex); + + if (client->dev.of_node) { + bma2xx_power_init(data, true); + bma2xx_parse_gpio(client); + err =of_property_read_u32(client->dev.of_node, "bma2xx,orientation", &val); + if (err) + dev_err(&client->dev, "get orientation fialed\n"); + else + data->orientation = val; + } + + /* read chip id */ + err = i2c_smbus_read_byte_data(client, BMA2XXX_CHIP_ID_REG); + if (err < 0) { + dev_err(&client->dev, "read chip id error, maybe not connected\n"); + goto power_deinit; + } + chipid = err; + pr_info("bma2xx chip id is 0x%x\n", chipid); + +#if defined(BMA2XXX_ENABLE_INT1) || defined(BMA2XXX_ENABLE_INT2) + bma2xx_set_Int_Mode(client, 1); /*latch interrupt 250ms */ +#endif + /*************** + 1,high g x + 2,high g y + 5,slope x + 8,single tap + 9,double tap + 10,orient + 11,flat + ***************/ + //bma2xx_set_Int_Enable(client, 8, 1); + //bma2xx_set_Int_Enable(client, 10, 1); + //bma2xx_set_Int_Enable(client, 11, 1); + +#ifdef BMA2XXX_ENABLE_INT1 + /* maps interrupt to INT1 pin */ + bma2xx_set_int1_pad_sel(client, PAD_LOWG); + bma2xx_set_int1_pad_sel(client, PAD_HIGHG); + bma2xx_set_int1_pad_sel(client, PAD_SLOP); + bma2xx_set_int1_pad_sel(client, PAD_DOUBLE_TAP); + bma2xx_set_int1_pad_sel(client, PAD_SINGLE_TAP); + bma2xx_set_int1_pad_sel(client, PAD_ORIENT); + bma2xx_set_int1_pad_sel(client, PAD_FLAT); +#endif + +#ifdef BMA2XXX_ENABLE_INT2 + /* maps interrupt to INT2 pin */ + bma2xx_set_int2_pad_sel(client, PAD_LOWG); + bma2xx_set_int2_pad_sel(client, PAD_HIGHG); + bma2xx_set_int2_pad_sel(client, PAD_SLOP); + bma2xx_set_int2_pad_sel(client, PAD_DOUBLE_TAP); + bma2xx_set_int2_pad_sel(client, PAD_SINGLE_TAP); + bma2xx_set_int2_pad_sel(client, PAD_ORIENT); + bma2xx_set_int2_pad_sel(client, PAD_FLAT); +#endif + +#if defined(BMA2XXX_ENABLE_INT1) || defined(BMA2XXX_ENABLE_INT2) + data->IRQ = gpio_to_irq(client->irq); + err = + request_irq(data->IRQ, bma2xx_irq_handler, IRQF_TRIGGER_RISING, + "bma2xx", data); + if (err) + printk(KERN_ERR "could not request irq\n"); + INIT_WORK(&data->irq_work, bma2xx_irq_work_func); +#endif + + INIT_DELAYED_WORK(&data->work, bma2xx_work_func); + atomic_set(&data->delay, BMA2XXX_MAX_DELAY); + atomic_set(&data->enable, 0); + + data->input = input_allocate_device(); + if (!data->input) { + dev_err(&client->dev, "allocate input device fail\n"); + goto power_deinit; + } + data->input->name = "zte_acc"; + data->input->id.bustype = BUS_I2C; + data->input->dev.parent = &data->bma2xx_client->dev; + + input_set_capability(data->input, EV_REL, LOW_G_INTERRUPT); + input_set_capability(data->input, EV_REL, HIGH_G_INTERRUPT); + input_set_capability(data->input, EV_REL, SLOP_INTERRUPT); + input_set_capability(data->input, EV_REL, DOUBLE_TAP_INTERRUPT); + input_set_capability(data->input, EV_REL, SINGLE_TAP_INTERRUPT); + input_set_capability(data->input, EV_ABS, ORIENT_INTERRUPT); + input_set_capability(data->input, EV_ABS, FLAT_INTERRUPT); + input_set_abs_params(data->input, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(data->input, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(data->input, ABS_Z, ABSMIN, ABSMAX, 0, 0); + set_bit(EV_REL, data->input->evbit); + set_bit(ABS_X, data->input->relbit); + set_bit(ABS_Y, data->input->relbit); + set_bit(ABS_Z, data->input->relbit); + + input_set_drvdata(data->input, data); + + err = input_register_device(data->input); + if (err < 0) { + input_free_device(data->input); + goto power_deinit; + } + + err = sysfs_create_group(&client->dev.kobj, &bma2xx_attribute_group); + if (err < 0) + goto error_sysfs; + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + data->early_suspend.suspend = bma2xx_early_suspend; + data->early_suspend.resume = bma2xx_late_resume; + register_early_suspend(&data->early_suspend); +#endif + printk("bma2xx probe success\n"); + return 0; + +error_sysfs: + input_unregister_device(data->input); +power_deinit: + bma2xx_power_init(data, false); + kfree(data); +exit: + printk("bma2xx probe failed\n"); + return err; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bma2xx_early_suspend(struct early_suspend *h) +{ + struct bma2xx_data *data = + container_of(h, struct bma2xx_data, early_suspend); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2xx_set_mode(data->bma2xx_client, BMA2XXX_MODE_SUSPEND); + cancel_delayed_work_sync(&data->work); + } + mutex_unlock(&data->enable_mutex); +} + +static void bma2xx_late_resume(struct early_suspend *h) +{ + struct bma2xx_data *data = + container_of(h, struct bma2xx_data, early_suspend); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2xx_set_mode(data->bma2xx_client, BMA2XXX_MODE_NORMAL); + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read + (&data->delay))); + } + mutex_unlock(&data->enable_mutex); +} +#endif + +static int __devexit bma2xx_remove(struct i2c_client *client) +{ + struct bma2xx_data *data = i2c_get_clientdata(client); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + bma2xx_power_init(data, false); + sysfs_remove_group(&data->input->dev.kobj, &bma2xx_attribute_group); + input_unregister_device(data->input); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM + +static int bma2xx_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct bma2xx_data *data = i2c_get_clientdata(client); + + if (data != NULL) { + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2xx_set_mode(data->bma2xx_client, BMA2XXX_MODE_SUSPEND); + cancel_delayed_work_sync(&data->work); + } + mutex_unlock(&data->enable_mutex); + } + return 0; +} + +static int bma2xx_resume(struct i2c_client *client) +{ + struct bma2xx_data *data = i2c_get_clientdata(client); + + if (data != NULL) { + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2xx_set_mode(data->bma2xx_client, BMA2XXX_MODE_NORMAL); + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read + (&data->delay))); + } + mutex_unlock(&data->enable_mutex); + } + + return 0; +} +#else + +#define bma2xx_suspend NULL +#define bma2xx_resume NULL + +#endif /* CONFIG_PM */ + +static ssize_t acc_info_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "0x%x\n", chipid); +} + +static struct proc_dir_entry *acc_info_proc_file; +static int __init create_acc_info_proc_file(void) +{ + if(0xff == chipid) { + printk("not create bma2xx proc file due to unconnected\n"); + return 0; + } + acc_info_proc_file = create_proc_entry("driver/accel", 0644, NULL); + printk("goes to create_acc_info_proc_file\n"); + if (acc_info_proc_file) { + acc_info_proc_file->read_proc = acc_info_read_proc; + } else{ + printk(KERN_INFO "proc file create failed!\n"); + } + return 0; +} + +static const struct i2c_device_id bma2xx_id[] = { + {SENSOR_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bma2xx_id); + +static const struct of_device_id bma2xx_of_match[] = { + {.compatible = "bcm,bma2xx",}, + {}, +} + +MODULE_DEVICE_TABLE(of, bma2xx_of_match); + +static struct i2c_driver bma2xx_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = bma2xx_of_match, + }, + .id_table = bma2xx_id, + .probe = bma2xx_probe, + .suspend = bma2xx_suspend, + .resume = bma2xx_resume, + .remove = __devexit_p(bma2xx_remove), + +}; + +MODULE_AUTHOR("Albert Zhang "); +MODULE_DESCRIPTION("BMA2XXX accelerometer sensor driver"); +MODULE_LICENSE("GPL"); + +module_i2c_driver(bma2xx_driver); +late_initcall(create_acc_info_proc_file); + diff --git a/drivers/misc/zte-sensor/mc3xxx.c b/drivers/misc/zte-sensor/mc3xxx.c new file mode 100644 index 000000000000..9e475e11c5e5 --- /dev/null +++ b/drivers/misc/zte-sensor/mc3xxx.c @@ -0,0 +1,1944 @@ +/***************************************************************************** + * + * Copyright (c) 2013 mCube, Inc. All rights reserved. + * + * This source is subject to the mCube Software License. + * This software is protected by Copyright and the information and source code + * contained herein is confidential. The software including the source code + * may not be copied and the information contained herein may not be used or + * disclosed except with the written permission of mCube Inc. + * + * All other rights reserved. + * + * This code and information are provided "as is" without warranty of any + * kind, either expressed or implied, including but not limited to the + * implied warranties of merchantability and/or fitness for a + * particular purpose. + * + * The following software/firmware and/or related documentation ("mCube Software") + * have been modified by mCube Inc. All revisions are subject to any receiver's + * applicable license agreements with mCube Inc. + * + * 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 +#include +#include +#include +#include + +#if 0 +#define GSENSOR_DBG(format, args...) printk(KERN_INFO "mc3xxx:%s( )_%d_: " format, \ + __FUNCTION__ , __LINE__, ## args); +#else +#define GSENSOR_DBG(format, args...); +#endif + +//=== CONFIGURATIONS ========================================================== +//#define DOT_CALI +#define _MC3XXX_DEBUG_ON_ +//============================================================================= +#ifdef _MC3XXX_DEBUG_ON_ + #define mcprintkreg(x...) printk(x) + #define mcprintkfunc(x...) printk(x) + #define GSE_ERR(x...) printk(x) + #define GSE_LOG(x...) printk(x) +#else + #define mcprintkreg(x...) + #define mcprintkfunc(x...) + #define GSE_ERR(x...) + #define GSE_LOG(x...) +#endif + +//============================================================================= +#define SENSOR_NAME "mc3xxx" +#define SENSOR_DRIVER_VERSION "1.1.0" +#define SENSOR_DATA_SIZE 3 +#define GRAVITY_1G_VALUE 1024 + +//============================================================================= +#define SENSOR_DMARD_IOCTL_BASE 234 + +#define IOCTL_SENSOR_SET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 100) +#define IOCTL_SENSOR_GET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 101) +#define IOCTL_SENSOR_GET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 102) +#define IOCTL_SENSOR_SET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 103) +#define IOCTL_SENSOR_GET_DATA_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 104) + +#define IOCTL_MSENSOR_SET_DELAY_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 200) +#define IOCTL_MSENSOR_GET_DATA_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 201) +#define IOCTL_MSENSOR_GET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 202) +#define IOCTL_MSENSOR_SET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 203) + +#define IOCTL_SENSOR_GET_NAME _IO(SENSOR_DMARD_IOCTL_BASE, 301) +#define IOCTL_SENSOR_GET_VENDOR _IO(SENSOR_DMARD_IOCTL_BASE, 302) + +#define IOCTL_SENSOR_GET_CONVERT_PARA _IO(SENSOR_DMARD_IOCTL_BASE, 401) +#define SENSOR_CALIBRATION _IOWR(SENSOR_DMARD_IOCTL_BASE, 402, int[SENSOR_DATA_SIZE]) + +//============================================================================= +#define MC3XXX_CONVERT_PARAMETER (1.5f * (9.80665f) / 256.0f) +#define MC3XXX_DIPLAY_VENDOR "mCube" +//============================================================================= +#define MC3XXX_DATA_LEN 6 + +#define MC3XXX_XOUT_REG 0x00 +#define MC3XXX_YOUT_REG 0x01 +#define MC3XXX_ZOUT_REG 0x02 +#define MC3XXX_Tilt_Status_REG 0x03 +#define MC3XXX_SAMPLING_RATE_STATUS_REG 0x04 +#define MC3XXX_SLEEP_COUNT_REG 0x05 +#define MC3XXX_INTERRUPT_ENABLE_REG 0x06 +#define MC3XXX_MODE_FEATURE_REG 0x07 +#define MC3XXX_SAMPLE_RATE_REG 0x08 +#define MC3XXX_TAP_DETECTION_ENABLE_REG 0x09 +#define MC3XXX_TAP_DWELL_REJECT_REG 0x0a +#define MC3XXX_DROP_CONTROL_REG 0x0b +#define MC3XXX_SHAKE_DEBOUNCE_REG 0x0c +#define MC3XXX_XOUT_EX_L_REG 0x0d +#define MC3XXX_XOUT_EX_H_REG 0x0e +#define MC3XXX_YOUT_EX_L_REG 0x0f +#define MC3XXX_YOUT_EX_H_REG 0x10 +#define MC3XXX_ZOUT_EX_L_REG 0x11 +#define MC3XXX_ZOUT_EX_H_REG 0x12 +#define MC3XXX_CHIP_ID_REG 0x18 +#define MC3XXX_RANGE_CONTROL_REG 0x20 +#define MC3XXX_SHAKE_THRESHOLD_REG 0x2B +#define MC3XXX_UD_Z_TH_REG 0x2C +#define MC3XXX_UD_X_TH_REG 0x2D +#define MC3XXX_RL_Z_TH_REG 0x2E +#define MC3XXX_RL_Y_TH_REG 0x2F +#define MC3XXX_FB_Z_TH_REG 0x30 +#define MC3XXX_DROP_THRESHOLD_REG 0x31 +#define MC3XXX_TAP_THRESHOLD_REG 0x32 +#define MC3XXX_PCODE_REG 0x3B + +#define MC3XXX_RESOLUTION_LOW 1 +#define MC3XXX_RESOLUTION_HIGH 2 + +#define MC3XXX_WAKE 1 +#define MC3XXX_SNIFF 2 +#define MC3XXX_STANDBY 3 + +/*********************************************** + *** RETURN CODE + ***********************************************/ +#define MC3XXX_RETCODE_SUCCESS (0) +#define MC3XXX_RETCODE_ERROR_I2C (-1) +#define MC3XXX_RETCODE_ERROR_STATUS (-3) +#define MC3XXX_RETCODE_ERROR_SETUP (-4) +#define MC3XXX_RETCODE_ERROR_GET_DATA (-5) +#define MC3XXX_RETCODE_ERROR_IDENTIFICATION (-6) + + +/*********************************************** + *** PRODUCT ID + ***********************************************/ +#define MC3XXX_PCODE_3210 0x90 +#define MC3XXX_PCODE_3230 0x19 +#define MC3XXX_PCODE_3250 0x88 +#define MC3XXX_PCODE_3410 0xA8 +#define MC3XXX_PCODE_3410N 0xB8 +#define MC3XXX_PCODE_3430 0x29 +#define MC3XXX_PCODE_3430N 0x39 +#define MC3XXX_PCODE_3510B 0x40 +#define MC3XXX_PCODE_3530B 0x30 +#define MC3XXX_PCODE_3510C 0x10 +#define MC3XXX_PCODE_3530C 0x60 + +//============================================================================= +#define MC3XXX_I2C_NAME SENSOR_NAME +#define SENSOR_DEV_COUNT 1 +#define SENSOR_DURATION_MAX 200 +#define SENSOR_DURATION_MIN 10 +#define SENSOR_DURATION_DEFAULT 100 + +#define MAX_RETRY 20 +#define INPUT_FUZZ 0 +#define INPUT_FLAT 0 + +#define MC3XXX_BUFSIZE 256 + +static unsigned char s_bResolution = 0x00; +static unsigned char s_bPCODE = 0x00; + +static unsigned short mc3xxx_i2c_auto_probe_addr[] = { 0x4C, 0x6C, 0x4E, 0x6D, 0x6E, 0x6F }; +typedef struct { + unsigned short x; /**< X axis */ + unsigned short y; /**< Y axis */ + unsigned short z; /**< Z axis */ +} GSENSOR_VECTOR3D; + +static GSENSOR_VECTOR3D gsensor_gain = { 0 }; +static struct miscdevice mc3xxx_device; +//============================================================================= +#ifdef DOT_CALI +static unsigned char is_new_mc34x0 = 0; +static unsigned char is_mc3250 = 0; +//#define CALIB_PATH "/data/data/com.mcube.acc/files/mcube-calib.txt" +#define DATA_PATH "/sdcard/mcube-register-map.txt" +static char file_path[MC3XXX_BUFSIZE] = "/data/data/com.mcube.acc/files/mcube-calib.txt"; +//static char factory_path[MC3XXX_BUFSIZE] ="/data/data/com.mcube.acc/files/fac-calib.txt"; + +static struct file * fd_file = NULL; +static mm_segment_t oldfs = { 0 }; +static unsigned char offset_buf[9] = { 0 }; +static signed int offset_data[3] = { 0 }; +static signed int gain_data[3] = { 0 }; +static signed int enable_RBM_calibration = 0; + +#define GSENSOR 0x95 +#define GSENSOR_IOCTL_INIT _IO(GSENSOR, 0x01) +#define GSENSOR_IOCTL_READ_CHIPINFO _IOR(GSENSOR, 0x02, int) +#define GSENSOR_IOCTL_READ_SENSORDATA _IOR(GSENSOR, 0x03, int) +#define GSENSOR_IOCTL_READ_RAW_DATA _IOR(GSENSOR, 0x06, int) +//#define GSENSOR_IOCTL_SET_CALI _IOW(GSENSOR, 0x06, SENSOR_DATA) +#define GSENSOR_IOCTL_GET_CALI _IOW(GSENSOR, 0x07, SENSOR_DATA) +#define GSENSOR_IOCTL_CLR_CALI _IO(GSENSOR, 0x08) +#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA _IOR(GSENSOR, 0x09, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE _IO(GSENSOR, 0x0a) +#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE _IO(GSENSOR, 0x0b) +#define GSENSOR_MCUBE_IOCTL_SET_CALI _IOW(GSENSOR, 0x0c, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP _IO(GSENSOR, 0x0d) + +typedef struct{ + int x; + int y; + int z; +}SENSOR_DATA; + +static int load_cali_flg = 0; +static unsigned char mc3xxx_current_placement = MC3XXX_BOTTOM_LEFT_UP; // current soldered placement + +enum mc3xxx_orientation +{ + MC3XXX_TOP_LEFT_DOWN = 0, + MC3XXX_TOP_RIGHT_DOWN, + MC3XXX_TOP_RIGHT_UP, + MC3XXX_TOP_LEFT_UP, + MC3XXX_BOTTOM_LEFT_DOWN, + MC3XXX_BOTTOM_RIGHT_DOWN, + MC3XXX_BOTTOM_RIGHT_UP, + MC3XXX_BOTTOM_LEFT_UP +}; +struct mc3xxx_hwmsen_convert +{ + signed char sign[3]; + unsigned char map[3]; +}; + +// Transformation matrix for chip mounting position +static const struct mc3xxx_hwmsen_convert mc3xxx_cvt[] = +{ + {{ 1, 1, 1}, {0, 1, 2}}, // 0: top , left-down + {{-1, 1, 1}, {1, 0, 2}}, // 1: top , right-down + {{-1, -1, 1}, {0, 1, 2}}, // 2: top , right-up + {{ 1, -1, 1}, {1, 0, 2}}, // 3: top , left-up + {{-1, 1, -1}, {0, 1, 2}}, // 4: bottom, left-down + {{ 1, 1, -1}, {1, 0, 2}}, // 5: bottom, right-down + {{ 1, -1, -1}, {0, 1, 2}}, // 6: bottom, right-up + {{-1, -1, -1}, {1, 0, 2}}, // 7: bottom, left-up +}; + +//============================================================================= +#define REMAP_IF_MC3250_READ(nDataX, nDataY) \ + if (MC3XXX_PCODE_3250 == s_bPCODE) \ + { \ + int _nTemp = 0; \ + \ + _nTemp = nDataX; \ + nDataX = nDataY; \ + nDataY = -_nTemp; \ + GSE_LOG("[%s] 3250 read remap\n", __FUNCTION__); \ + } + +#define REMAP_IF_MC3250_WRITE(nDataX, nDataY) \ + if (MC3XXX_PCODE_3250 == s_bPCODE) \ + { \ + int _nTemp = 0; \ + \ + _nTemp = nDataX; \ + nDataX = -nDataY; \ + nDataY = _nTemp; \ + GSE_LOG("[%s] 3250 write remap\n", __FUNCTION__); \ + } + +#define REMAP_IF_MC34XX_N(nDataX, nDataY) \ + if ((MC3XXX_PCODE_3410N == s_bPCODE) || (MC3XXX_PCODE_3430N == s_bPCODE)) \ + { \ + nDataX = -nDataX; \ + nDataY = -nDataY; \ + GSE_LOG("[%s] 34X0N remap\n", __FUNCTION__); \ + } + +#define REMAP_IF_MC35XX(nDataX, nDataY) \ + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE) || (MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == s_bPCODE)) \ + { \ + nDataX = -nDataX; \ + nDataY = -nDataY; \ + GSE_LOG("[%s] 35X0 remap\n", __FUNCTION__); \ + } +#endif // END OF #ifdef DOT_CALI + +#define IS_MC35XX() ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE) || (MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == s_bPCODE)) + +struct mc3xxx_data { + struct mutex lock; + struct i2c_client *client; + struct work_struct work; + struct workqueue_struct *mc3xxx_wq; + struct hrtimer timer; + struct input_dev *input_dev; + int enabled; + volatile unsigned int duration; + + int axis_map_x; + int axis_map_y; + int axis_map_z; + int negate_x; + int negate_y; + int negate_z; + bool vdd_enabled; + bool vio_enabled; + struct regulator *vdd; + struct regulator *vio; +}; + +static int mc3xxx_enable(struct mc3xxx_data *data, int enable); +static int mc3xxx_power_init(struct mc3xxx_data *data, bool on); + +#ifdef CONFIG_OF +#define MC3XXX_VDD_MIN_UV 2700000 +#define MC3XXX_VDD_MAX_UV 3300000 +#define MC3XXX_VIO_MIN_UV 1700000 +#define MC3XXX_VIO_MAX_UV 1950000 +#endif + +/***************************************** + *** mc3xxx_validate_sensor_IC + //checks if the product is mCube or not. + // Thus, the return code is TRUE/FALSE instead of Product-ID. + *****************************************/ +static int mc3xxx_validate_sensor_IC(unsigned char bPCode) +{ + GSENSOR_DBG(); + if ( (MC3XXX_PCODE_3210 == bPCode) || (MC3XXX_PCODE_3230 == bPCode) + || (MC3XXX_PCODE_3250 == bPCode) + || (MC3XXX_PCODE_3410 == bPCode) || (MC3XXX_PCODE_3430 == bPCode) + || (MC3XXX_PCODE_3410N == bPCode) || (MC3XXX_PCODE_3430N == bPCode) + || (MC3XXX_PCODE_3510B == bPCode) || (MC3XXX_PCODE_3530B == bPCode) + || (MC3XXX_PCODE_3510C == bPCode) || (MC3XXX_PCODE_3530C == bPCode) ) + { + return (MC3XXX_RETCODE_SUCCESS); + } + + return (MC3XXX_RETCODE_ERROR_IDENTIFICATION); +} +/***************************************** + *** MC3XXX_SetResolution + *****************************************/ +static void mc3xxx_set_resolution(void) +{ + GSENSOR_DBG(); + switch (s_bPCODE) + { + case MC3XXX_PCODE_3230: + case MC3XXX_PCODE_3430: + case MC3XXX_PCODE_3430N: + case MC3XXX_PCODE_3530B: + case MC3XXX_PCODE_3530C: + s_bResolution = MC3XXX_RESOLUTION_LOW; + break; + + case MC3XXX_PCODE_3210: + case MC3XXX_PCODE_3250: + case MC3XXX_PCODE_3410: + case MC3XXX_PCODE_3410N: + case MC3XXX_PCODE_3510B: + case MC3XXX_PCODE_3510C: + s_bResolution = MC3XXX_RESOLUTION_HIGH; + break; + + default: + GSE_ERR("ERR: no resolution assigned!\n"); + break; + } + + GSE_LOG("[%s] s_bResolution: %d\n", __FUNCTION__, s_bResolution); +} + +/***************************************** + *** MC3XXX_ConfigRegRange + *****************************************/ +static void mc3xxx_config_regRange(struct i2c_client *client) +{ + unsigned char _baDataBuf[2] = { 0 }; + + _baDataBuf[0] = MC3XXX_RANGE_CONTROL_REG; + _baDataBuf[1] = 0x3F; + GSENSOR_DBG(); + if (MC3XXX_RESOLUTION_LOW == s_bResolution) + _baDataBuf[1] = 0x32; + + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE)) + _baDataBuf[1] = 0xA5; + else if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == s_bPCODE)) + _baDataBuf[1] = 0x02; + + i2c_smbus_write_byte_data(client, _baDataBuf[0], _baDataBuf[1]); + + GSE_LOG("[%s] set 0x%X\n", __FUNCTION__, _baDataBuf[1]); +} + +/***************************************** + *** MC3XXX_SetGain + *****************************************/ +static void mc3xxx_set_gain(void) +{ + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; + GSENSOR_DBG(); + if (MC3XXX_RESOLUTION_LOW == s_bResolution) + { + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86; + + if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == s_bPCODE)) + { + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 64; + } + } + + GSE_LOG("[%s] gain: %d / %d / %d\n", __FUNCTION__, gsensor_gain.x, gsensor_gain.y, gsensor_gain.z); +} + +static ssize_t mc3xxx_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mc3xxx_data *mc3xxx = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", mc3xxx->enabled); +} + +//============================================================================= +static ssize_t mc3xxx_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mc3xxx_data *mc3xxx = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + printk("mc3xxx set poll enable %ld\n", val); + mc3xxx_enable(mc3xxx, val); + + return count; +} + +//============================================================================= +static ssize_t mc3xxx_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mc3xxx_data *mc3xxx = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", mc3xxx->duration); +} + +//============================================================================= +static ssize_t mc3xxx_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mc3xxx_data *mc3xxx = dev_get_drvdata(dev); + unsigned long data = 0; + + if(strict_strtoul(buf, 10, &data)) + return -EINVAL; + + if (data > SENSOR_DURATION_MAX) + data = SENSOR_DURATION_MAX; + if (data < SENSOR_DURATION_MIN) + data = SENSOR_DURATION_MIN; + + mc3xxx->duration = data; + + return count; +} + +//============================================================================= + +static struct device_attribute mc3xxx_attrs[] = +{ + __ATTR(enable_device, S_IRUGO | S_IWUSR | S_IWGRP, mc3xxx_enable_show, mc3xxx_enable_store), + __ATTR(pollrate_ms, S_IRUGO | S_IWUSR | S_IWGRP, mc3xxx_delay_show, mc3xxx_delay_store), +}; + +static int create_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mc3xxx_attrs); i++) + if (device_create_file(dev, mc3xxx_attrs + i)) + goto error; + return 0; + +error: + for ( ; i >= 0; i--) + device_remove_file(dev, mc3xxx_attrs + i); + dev_err(dev, "%s:Unable to create interface\n", __func__); + return -1; +} + +static int remove_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mc3xxx_attrs); i++) + device_remove_file(dev, mc3xxx_attrs + i); + return 0; +} + +int mc3xxx_set_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data = 0; + GSENSOR_DBG(); + if (mode < 4) + { + data = (0x40 | mode); + comres = i2c_smbus_write_byte_data(client, MC3XXX_MODE_FEATURE_REG, data); + } + + return comres; +} + +//============================================================================= +static int mc3xxx_chip_init(struct i2c_client *client) +{ + unsigned char _baDataBuf[2] = { 0 }; + GSENSOR_DBG(); + + mc3xxx_set_mode(client, MC3XXX_STANDBY); + //Louis, test code ================================================== + // config HIGH resolution + if ((0x10 == s_bPCODE) || (0x60 == s_bPCODE)) + s_bPCODE = 0x60; + //Louis, test code ================================================== + + mc3xxx_set_resolution(); + + _baDataBuf[0] = MC3XXX_SAMPLE_RATE_REG; + _baDataBuf[1] = 0x00; + if (IS_MC35XX()) + _baDataBuf[1] = 0x0A; + i2c_smbus_write_byte_data(client, _baDataBuf[0], _baDataBuf[1]); + _baDataBuf[0] = MC3XXX_TAP_DETECTION_ENABLE_REG; + _baDataBuf[1] = 0x00; + i2c_smbus_write_byte_data(client, _baDataBuf[0], _baDataBuf[1]); + _baDataBuf[0] = MC3XXX_INTERRUPT_ENABLE_REG; + _baDataBuf[1] = 0x00; + i2c_smbus_write_byte_data(client, _baDataBuf[0], _baDataBuf[1]); + + mc3xxx_config_regRange(client); + mc3xxx_set_gain(); + return 0; +} + +#ifdef DOT_CALI +//============================================================================= +struct file *openFile(char *path, int flag, int mode) +{ + struct file *fp = NULL; + GSENSOR_DBG(); + fp = filp_open(path, flag, mode); + + if (IS_ERR(fp) || !fp->f_op) + { + GSE_LOG("Calibration File filp_open return NULL\n"); + return NULL; + } + + return fp; +} + +//============================================================================= +int readFile(struct file *fp, char *buf, int readlen) +{ + GSENSOR_DBG(); + if (fp->f_op && fp->f_op->read) + return fp->f_op->read(fp,buf,readlen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int writeFile(struct file *fp, char *buf, int writelen) +{ + GSENSOR_DBG(); + if (fp->f_op && fp->f_op->write) + return fp->f_op->write(fp,buf,writelen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int closeFile(struct file *fp) +{ + GSENSOR_DBG(); + filp_close(fp, NULL); + + return 0; +} + +//============================================================================= +void initKernelEnv(void) +{ + GSENSOR_DBG(); + oldfs = get_fs(); + set_fs(KERNEL_DS); + printk(KERN_INFO "initKernelEnv\n"); +} + +//============================================================================= +int MC3XXX_WriteCalibration(struct i2c_client *client, int dat[3]) +{ + int err = 0; + u8 buf[9] = { 0 }; + s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + s32 x_off = 0, y_off = 0, z_off = 0; + int temp_cali_dat[3] = { 0 }; + const struct mc3xxx_hwmsen_convert *pCvt = NULL; + + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + s32 dwRangePosLimit = 0x1FFF; + s32 dwRangeNegLimit = -0x2000; + + pCvt = &mc3xxx_cvt[mc3xxx_current_placement]; + GSENSOR_DBG(); + temp_cali_dat[pCvt->map[0]] = pCvt->sign[0] * dat[0]; + temp_cali_dat[pCvt->map[1]] = pCvt->sign[1] * dat[1]; + temp_cali_dat[pCvt->map[2]] = pCvt->sign[2] * dat[2]; + + temp_cali_dat[0] = ((temp_cali_dat[0] * gsensor_gain.x) / GRAVITY_1G_VALUE); + temp_cali_dat[1] = ((temp_cali_dat[1] * gsensor_gain.y) / GRAVITY_1G_VALUE); + temp_cali_dat[2] = ((temp_cali_dat[2] * gsensor_gain.z) / GRAVITY_1G_VALUE); + + REMAP_IF_MC3250_READ(temp_cali_dat[0], temp_cali_dat[1]); + REMAP_IF_MC34XX_N(temp_cali_dat[0], temp_cali_dat[1]); + REMAP_IF_MC35XX(temp_cali_dat[0], temp_cali_dat[1]); + + dat[0] = temp_cali_dat[0]; + dat[1] = temp_cali_dat[1]; + dat[2] = temp_cali_dat[2]; + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", dat[0], dat[1], dat[2]); + + // read register 0x21~0x29 + err = i2c_smbus_read_i2c_block_data(client , 0x21 , 3 , &buf[0]); + err |= i2c_smbus_read_i2c_block_data(client , 0x24 , 3 , &buf[3]); + err |= i2c_smbus_read_i2c_block_data(client , 0x27 , 3 , &buf[6]); + + + + if (IS_MC35XX()) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + dwRangePosLimit = 0x3FFF; + dwRangeNegLimit = -0x4000; + } + + // get x,y,z offset + tmp = ((buf[1] & bMsbFilter) << 8) + buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + x_off = tmp; + + tmp = ((buf[3] & bMsbFilter) << 8) + buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + y_off = tmp; + + tmp = ((buf[5] & bMsbFilter) << 8) + buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + z_off = tmp; + + // get x,y,z gain + x_gain = ((buf[1] >> 7) << 8) + buf[6]; + y_gain = ((buf[3] >> 7) << 8) + buf[7]; + z_gain = ((buf[5] >> 7) << 8) + buf[8]; + + // prepare new offset + x_off = x_off + 16 * dat[0] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain); + y_off = y_off + 16 * dat[1] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain); + z_off = z_off + 16 * dat[2] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain); + + // range check + if (x_off > dwRangePosLimit) + x_off = dwRangePosLimit; + else if (x_off < dwRangeNegLimit) + x_off = dwRangeNegLimit; + + if (y_off > dwRangePosLimit) + y_off = dwRangePosLimit; + else if (y_off < dwRangeNegLimit) + y_off = dwRangeNegLimit; + + if (z_off > dwRangePosLimit) + z_off = dwRangePosLimit; + else if (z_off < dwRangeNegLimit) + z_off = dwRangeNegLimit; + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + GSE_LOG("%d %d ======================\n\n ", gain_data[0], x_gain); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = x_off & 0xff; + buf[1] = ((x_off >> 8) & bMsbFilter) | (x_gain & 0x0100 ? 0x80 : 0); + buf[2] = y_off & 0xff; + buf[3] = ((y_off >> 8) & bMsbFilter) | (y_gain & 0x0100 ? 0x80 : 0); + buf[4] = z_off & 0xff; + buf[5] = ((z_off >> 8) & bMsbFilter) | (z_gain & 0x0100 ? 0x80 : 0); + + i2c_smbus_write_i2c_block_data(client, 0x21, 2, &buf[0]); + i2c_smbus_write_i2c_block_data(client, 0x21+2, 2, &buf[2]); + i2c_smbus_write_i2c_block_data(client, 0x21+4, 2, &buf[4]); + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + + msleep(50); + + return err; +} + +//============================================================================= +int mcube_read_cali_file(struct i2c_client *client) +{ + int cali_data[3] = { 0 }; + int err = 0; + char buf[64] = { 0 }; + GSENSOR_DBG(); + GSE_LOG("%s %d\n",__func__,__LINE__); + + initKernelEnv(); + + fd_file = openFile(file_path, O_RDONLY, 0); + + if (fd_file == NULL) + { + GSE_LOG("mc3xxx fail to open\n"); + cali_data[0] = 0; + cali_data[1] = 0; + cali_data[2] = 0; + + return -1; + } + else + { + memset(buf, 0, sizeof(buf)); + + if ((err = readFile(fd_file, buf, sizeof(buf))) > 0) + GSE_LOG("buf:%s\n",buf); + else + GSE_LOG("read file error %d\n",err); + + set_fs(oldfs); + closeFile(fd_file); + + sscanf(buf, "%d %d %d", &cali_data[0], &cali_data[1], &cali_data[2]); + GSE_LOG("cali_data: %d %d %d\n", cali_data[0], cali_data[1], cali_data[2]); + + MC3XXX_WriteCalibration(client, cali_data); + } + + return 0; +} + +//============================================================================= +static int mcube_write_log_data(struct i2c_client *client, u8 data[0x3f]) +{ + #define _WRT_LOG_DATA_BUFFER_SIZE (66 * 50) + + s16 rbm_data[3]={0}, raw_data[3]={0}; + int err =0; + char *_pszBuffer = NULL; + int n=0,i=0; + GSENSOR_DBG(); + initKernelEnv(); + fd_file = openFile(DATA_PATH ,O_RDWR | O_CREAT,0); + if (fd_file == NULL) + { + GSE_LOG("mcube_write_log_data fail to open\n"); + } + else + { + rbm_data[0] = (s16)((data[0x0d]) | (data[0x0e] << 8)); + rbm_data[1] = (s16)((data[0x0f]) | (data[0x10] << 8)); + rbm_data[2] = (s16)((data[0x11]) | (data[0x12] << 8)); + + raw_data[0] = (rbm_data[0] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + raw_data[1] = (rbm_data[1] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + raw_data[2] = (rbm_data[2] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + _pszBuffer = kzalloc(_WRT_LOG_DATA_BUFFER_SIZE, GFP_KERNEL); + if (NULL == _pszBuffer) + { + GSE_ERR("fail to allocate memory for buffer\n"); + closeFile(fd_file); + return -1; + } + memset(_pszBuffer, 0, _WRT_LOG_DATA_BUFFER_SIZE); + + n += sprintf(_pszBuffer+n, "G-sensor RAW X = %d Y = %d Z = %d\n", raw_data[0] ,raw_data[1] ,raw_data[2]); + n += sprintf(_pszBuffer+n, "G-sensor RBM X = %d Y = %d Z = %d\n", rbm_data[0] ,rbm_data[1] ,rbm_data[2]); + for(i=0; i<64; i++) + { + n += sprintf(_pszBuffer+n, "mCube register map Register[%x] = 0x%x\n",i,data[i]); + } + msleep(50); + if ((err = writeFile(fd_file,_pszBuffer,n))>0) + GSE_LOG("buf:%s\n",_pszBuffer); + else + GSE_LOG("write file error %d\n",err); + + kfree(_pszBuffer); + + set_fs(oldfs); + closeFile(fd_file); + } + return 0; +} + +//============================================================================= +void MC3XXX_rbm(struct i2c_client *client, int enable) +{ + char buf1[3] = { 0 }; + GSENSOR_DBG(); + if (enable == 1) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x02; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 1; + + GSE_LOG("set rbm!!\n"); + + msleep(220); + } + else if(enable == 0 ) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 0; + + GSE_LOG("clear rbm!!\n"); + + msleep(220); + } +} + +//============================================================================= +int MC3XXX_ReadOffset(struct i2c_client *client,s16 ofs[3]) +{ + int err = 0; + u8 off_data[6] = { 0 }; + GSENSOR_DBG(); + if(MC3XXX_RESOLUTION_HIGH == s_bResolution) + { + err = i2c_smbus_read_i2c_block_data(client, MC3XXX_XOUT_EX_L_REG, MC3XXX_DATA_LEN, off_data); + + ofs[0] = ((s16)(off_data[0]))|((s16)(off_data[1])<<8); + ofs[1] = ((s16)(off_data[2]))|((s16)(off_data[3])<<8); + ofs[2] = ((s16)(off_data[4]))|((s16)(off_data[5])<<8); + } + else if(MC3XXX_RESOLUTION_LOW == s_bResolution) + { + err = i2c_smbus_read_i2c_block_data(client, 0, 3, off_data); + + ofs[0] = (s8)off_data[0]; + ofs[1] = (s8)off_data[1]; + ofs[2] = (s8)off_data[2]; + } + REMAP_IF_MC3250_READ(ofs[0], ofs[1]); + REMAP_IF_MC34XX_N(ofs[0], ofs[1]); + REMAP_IF_MC35XX(ofs[0], ofs[1]); + + GSE_LOG("MC3XXX_ReadOffset %d %d %d\n", ofs[0], ofs[1], ofs[2]); + + return err; +} + +//============================================================================= +int MC3XXX_ResetCalibration(struct i2c_client *client) +{ + u8 buf[6] = { 0 }; + s16 tmp = 0; + int err = 0; + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + GSENSOR_DBG(); + buf[0] = 0x43; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error 0x07: %d\n", err); + } + + err = i2c_smbus_write_i2c_block_data(client, 0x21, 6, offset_buf); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + buf[0] = 0x41; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + msleep(20); + + + if (IS_MC35XX()) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + } + + tmp = ((offset_buf[1] & bMsbFilter) << 8) + offset_buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[0] = tmp; + + tmp = ((offset_buf[3] & bMsbFilter) << 8) + offset_buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[1] = tmp; + + tmp = ((offset_buf[5] & bMsbFilter) << 8) + offset_buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[2] = tmp; + + return 0; +} + +//============================================================================= +int MC3XXX_ReadCalibration(struct i2c_client *client, int dat[3]) +{ + signed short MC_offset[3 + 1] = { 0 }; // +1: for 4-byte alignment + int err = 0; + GSENSOR_DBG(); + memset(MC_offset, 0, sizeof(MC_offset)); + + err = MC3XXX_ReadOffset(client, MC_offset); + + if (err) + { + GSE_ERR("read offset fail, %d\n", err); + return err; + } + + dat[0] = MC_offset[0]; + dat[1] = MC_offset[1]; + dat[2] = MC_offset[2]; + + return 0; +} + +//============================================================================= +int MC3XXX_ReadData(struct i2c_client *client, s16 buffer[3]) +{ + unsigned char buf[6] = { 0 }; + signed char buf1[6] = { 0 }; + char rbm_buf[6] = { 0 }; + int ret = 0; + GSENSOR_DBG(); + if (enable_RBM_calibration == 0) + { + //err = hwmsen_read_block(client, addr, buf, 0x06); + } + else if (enable_RBM_calibration == 1) + { + memset(rbm_buf, 0, 6); + i2c_smbus_read_i2c_block_data(client, 0x0d , 2, &rbm_buf[0]); + i2c_smbus_read_i2c_block_data(client, 0x0d+2, 2, &rbm_buf[2]); + i2c_smbus_read_i2c_block_data(client, 0x0d+4, 2, &rbm_buf[4]); + } + + if (enable_RBM_calibration == 0) + { + if(MC3XXX_RESOLUTION_HIGH == s_bResolution) + + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_XOUT_EX_L_REG, 6, buf); + + buffer[0] = (signed short)((buf[0])|(buf[1]<<8)); + buffer[1] = (signed short)((buf[2])|(buf[3]<<8)); + buffer[2] = (signed short)((buf[4])|(buf[5]<<8)); + } + + else if(MC3XXX_RESOLUTION_LOW == s_bResolution) + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_XOUT_REG, 3, buf1); + + buffer[0] = (signed short)buf1[0]; + buffer[1] = (signed short)buf1[1]; + buffer[2] = (signed short)buf1[2]; + } + + } + else if (enable_RBM_calibration == 1) + { + buffer[0] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + buffer[1] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + buffer[2] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + if(gain_data[0] == 0) + { + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0; + + return 0; + } + + buffer[0] = (buffer[0] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + buffer[1] = (buffer[1] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + buffer[2] = (buffer[2] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + } + + return 0; +} + +//============================================================================= +int MC3XXX_ReadRawData(struct i2c_client *client, char * buf) +{ + int res = 0; + s16 raw_buf[3] = { 0 }; + GSENSOR_DBG(); + if (!buf || !client) + { + return -EINVAL; + } + + mc3xxx_set_mode(client, MC3XXX_WAKE); + res = MC3XXX_ReadData(client, &raw_buf[0]); + if(res) + { + GSE_ERR("I2C error: ret value=%d", res); + return -EIO; + } + else + { + const struct mc3xxx_hwmsen_convert *pCvt = &mc3xxx_cvt[mc3xxx_current_placement]; + raw_buf[0] = ((raw_buf[0] * GRAVITY_1G_VALUE) / gsensor_gain.x); + raw_buf[1] = ((raw_buf[1] * GRAVITY_1G_VALUE) / gsensor_gain.y); + raw_buf[2] = ((raw_buf[2] * GRAVITY_1G_VALUE) / gsensor_gain.z); + + if (is_new_mc34x0) + { + raw_buf[0] = -raw_buf[0]; + raw_buf[1] = -raw_buf[1]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_buf[0]; + + raw_buf[0] = raw_buf[1]; + raw_buf[1] = -temp; + } + + raw_buf[0] = pCvt->sign[0] * raw_buf[pCvt->map[0]]; + raw_buf[1] = pCvt->sign[1] * raw_buf[pCvt->map[1]]; + raw_buf[2] = pCvt->sign[2] * raw_buf[pCvt->map[2]]; + + sprintf(buf, "%04x %04x %04x", raw_buf[0], raw_buf[1], raw_buf[2]); + } + + return 0; +} + +//============================================================================= +static int MC3XXX_ReadRegMap(struct i2c_client *client) +{ + u8 data[128] = {0}; + u8 addr = 0x00; + int err = 0; + int i = 0; + GSENSOR_DBG(); + if(NULL == client) + { + err = -EINVAL; + return err; + } + + for (i = 0; i < 11; i++) + { + err |= i2c_smbus_read_i2c_block_data(client, addr, 6, &data[addr]); + addr +=6; + } + + for(i = 0; i < 64; i++) + printk(KERN_INFO "mcube register map Register[%x] = 0x%x\n", i ,data[i]); + + msleep(50); + + mcube_write_log_data(client, data); + + msleep(50); + + return err; +} + +//============================================================================= +void MC3XXX_Reset(struct i2c_client *client) +{ + s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + s32 x_off = 0, y_off = 0, z_off = 0; + u8 buf[3] = { 0 }; + int err = 0; + GSENSOR_DBG(); + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = 0x6d; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + msleep(5); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + memset(offset_buf, 0, 9); + + err = i2c_smbus_read_i2c_block_data(client, 0x21, 9, offset_buf); + + tmp = ((offset_buf[1] & 0x3f) << 8) + offset_buf[0]; + if (tmp & 0x2000) + tmp |= 0xc000; + x_off = tmp; + + tmp = ((offset_buf[3] & 0x3f) << 8) + offset_buf[2]; + if (tmp & 0x2000) + tmp |= 0xc000; + y_off = tmp; + + tmp = ((offset_buf[5] & 0x3f) << 8) + offset_buf[4]; + if (tmp & 0x2000) + tmp |= 0xc000; + z_off = tmp; + + // get x,y,z gain + x_gain = ((offset_buf[1] >> 7) << 8) + offset_buf[6]; + y_gain = ((offset_buf[3] >> 7) << 8) + offset_buf[7]; + z_gain = ((offset_buf[5] >> 7) << 8) + offset_buf[8]; + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + + GSE_LOG("offser gain = %d %d %d %d %d %d======================\n\n ", + gain_data[0], gain_data[1], gain_data[2], offset_data[0], offset_data[1], offset_data[2]); +} + +#endif + +//============================================================================= +int mc3xxx_read_accel_xyz(struct mc3xxx_data *data, int *acc) +{ + int comres = 0; + s16 raw_data[3] = { 0 }; + +#ifdef DOT_CALI + comres = MC3XXX_ReadData(data->client, &raw_data[0]); +#else + unsigned char raw_buf[6] = { 0 }; + signed char raw_buf1[3] = { 0 }; + + if(MC3XXX_RESOLUTION_HIGH == s_bResolution) + { + comres = i2c_smbus_read_i2c_block_data(data->client, MC3XXX_XOUT_EX_L_REG, 6, raw_buf); + + raw_data[0] = (signed short)((raw_buf[0])|(raw_buf[1]<<8)); + raw_data[1] = (signed short)((raw_buf[2])|(raw_buf[3]<<8)); + raw_data[2] = (signed short)((raw_buf[4])|(raw_buf[5]<<8)); + } + + else if(MC3XXX_RESOLUTION_LOW == s_bResolution) + { + comres = i2c_smbus_read_i2c_block_data(data->client, MC3XXX_XOUT_REG, 3, raw_buf1); + + raw_data[0] = (signed short)raw_buf1[0]; + raw_data[1] = (signed short)raw_buf1[1]; + raw_data[2] = (signed short)raw_buf1[2]; + } + #endif + + raw_data[0] = ((raw_data[0] * GRAVITY_1G_VALUE) / gsensor_gain.x); + raw_data[1] = ((raw_data[1] * GRAVITY_1G_VALUE) / gsensor_gain.y); + raw_data[2] = ((raw_data[2] * GRAVITY_1G_VALUE) / gsensor_gain.z); + + acc[0] = ((data->negate_x) ? (-raw_data[data->axis_map_x]): (raw_data[data->axis_map_x])); + acc[1] = ((data->negate_y) ? (-raw_data[data->axis_map_y]): (raw_data[data->axis_map_y])); + acc[2] = ((data->negate_z) ? (-raw_data[data->axis_map_z]): (raw_data[data->axis_map_z])); + + return comres; +} + +//============================================================================= +static int mc3xxx_measure(struct mc3xxx_data *data, int *accel) +{ + #ifdef DOT_CALI + int ret = 0; + + if( load_cali_flg > 0) + { + ret = mcube_read_cali_file(data->client); + + if(ret == 0) + load_cali_flg = ret; + else + load_cali_flg--; + + GSE_LOG("load_cali %d\n",ret); + } + #endif + GSENSOR_DBG(); + + mc3xxx_read_accel_xyz(data, accel); + + return 0; +} + +//============================================================================= +static void mc3xxx_work_func(struct work_struct *work) +{ + struct mc3xxx_data *data = container_of(work, struct mc3xxx_data, work); + int accel[3] = { 0 }; + GSENSOR_DBG(); + mc3xxx_measure(data, accel); + + input_report_abs(data->input_dev, ABS_X, accel[0]); + input_report_abs(data->input_dev, ABS_Y, accel[1]); + input_report_abs(data->input_dev, ABS_Z, accel[2]); + input_sync(data->input_dev); +} + +//============================================================================= +static enum hrtimer_restart mc3xxx_timer_func(struct hrtimer *timer) +{ + struct mc3xxx_data *data = container_of(timer, struct mc3xxx_data, timer); + + queue_work(data->mc3xxx_wq, &data->work); + + hrtimer_start(&data->timer, ktime_set(0, data->duration * 1000000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +//============================================================================= +static int mc3xxx_enable(struct mc3xxx_data *data, int enable) +{ + if(enable) + { + mc3xxx_power_init(data, true); + mc3xxx_chip_init(data->client); + mc3xxx_set_mode(data->client, MC3XXX_WAKE); + hrtimer_start(&data->timer, ktime_set(0, data->duration * 1000000), HRTIMER_MODE_REL); + data->enabled = true; + } + else + { + hrtimer_cancel(&data->timer); + mc3xxx_set_mode(data->client, MC3XXX_STANDBY); + data->enabled = false; + mc3xxx_power_init(data, false); + } + + return 0; +} + +//============================================================================= +static long mc3xxx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; +#ifdef DOT_CALI + void __user *data1 = NULL; + char strbuf[256] = { 0 }; + int cali[3] = { 0 }; + SENSOR_DATA sensor_data = { 0 }; +#endif + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); + struct mc3xxx_data *data = NULL; + + data = i2c_get_clientdata(client); + switch (cmd) { +#ifdef DOT_CALI + case GSENSOR_IOCTL_READ_SENSORDATA: + case GSENSOR_IOCTL_READ_RAW_DATA: + case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA: + mutex_lock(&data->lock); + MC3XXX_ReadRawData(client, strbuf); + mutex_unlock(&data->lock); + + if (copy_to_user((void __user *) arg, &strbuf, strlen(strbuf)+1)) { + printk("failed to copy sense data to user space."); + return -EFAULT; + } + break; + + case GSENSOR_MCUBE_IOCTL_SET_CALI: + data1 = (void __user *)arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + if(copy_from_user(&sensor_data, data1, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + else + { + cali[0] = sensor_data.x; + cali[1] = sensor_data.y; + cali[2] = sensor_data.z; + + mutex_lock(&data->lock); + ret = MC3XXX_WriteCalibration(client, cali); + mutex_unlock(&data->lock); + } + break; + + case GSENSOR_IOCTL_CLR_CALI: + mutex_lock(&data->lock); + ret = MC3XXX_ResetCalibration(client); + mutex_unlock(&data->lock); + break; + + case GSENSOR_IOCTL_GET_CALI: + data1 = (unsigned char*)arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if((ret = MC3XXX_ReadCalibration(client, cali))) + { + GSE_LOG("fwq mc3xxx MC3XXX_ReadCalibration error!!!!\n"); + break; + } + + sensor_data.x = cali[0]; + sensor_data.y = cali[1]; + sensor_data.z = cali[2]; + + if(copy_to_user(data1, &sensor_data, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + break; + + case GSENSOR_MCUBE_IOCTL_SET_RBM_MODE: + mutex_lock(&data->lock); + MC3XXX_rbm(client, 1); + mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE: + mutex_lock(&data->lock); + MC3XXX_rbm(client, 0); + mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_REGISTER_MAP: + MC3XXX_ReadRegMap(client); + break; +#endif + default: + ret = -EINVAL; + break; + } + + return ret; +} + +//============================================================================= +static int mc3xxx_open(struct inode *inode, struct file *filp) +{ + return nonseekable_open(inode, filp); +} + +//============================================================================= +static int mc3xxx_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +//============================================================================= +static struct file_operations sensor_fops = +{ + .owner = THIS_MODULE, + .open = mc3xxx_open, + .release = mc3xxx_release, + .unlocked_ioctl = mc3xxx_ioctl, +}; + +//============================================================================= +static int mc3xxx_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mc3xxx_data *data = i2c_get_clientdata(client); + + if (data != NULL){ + hrtimer_cancel(&data->timer); + if (data->enabled) + mc3xxx_set_mode(data->client, MC3XXX_STANDBY); + } + return 0; +} + +//============================================================================= +static int mc3xxx_resume(struct i2c_client *client) +{ + struct mc3xxx_data *data = i2c_get_clientdata(client); + + if (data != NULL){ + if (data->enabled){ + mc3xxx_chip_init(data->client); +#ifdef DOT_CALI + MC3XXX_ResetCalibration(data->client); + mcube_read_cali_file(data->client); +#endif + mc3xxx_set_mode(data->client, MC3XXX_WAKE); + hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + } + return 0; +} + +//============================================================================= +static struct miscdevice mc3xxx_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_NAME, + .fops = &sensor_fops, +}; + +/***************************************** + *** _mc3xxx_i2c_auto_probe + *****************************************/ +static int mc3xxx_i2c_auto_probe(struct i2c_client *client) +{ + unsigned char _baDataBuf[2] = {0}; + int _nProbeAddrCount = (sizeof(mc3xxx_i2c_auto_probe_addr) / sizeof(mc3xxx_i2c_auto_probe_addr[0])); + int _nCount = 0; + + //i2c_smbus_read_byte_data(client, 0x3B); + s_bPCODE = 0x00; + GSENSOR_DBG(); + + for (_nCount = 0; _nCount < _nProbeAddrCount; _nCount++) + { + client->addr = mc3xxx_i2c_auto_probe_addr[_nCount]; + GSE_LOG("[%s] probing addr: 0x%X\n", __FUNCTION__, client->addr); + _baDataBuf[0] = MC3XXX_PCODE_REG; + if (0 > i2c_master_send(client, &(_baDataBuf[0]), 1)) + { + GSE_ERR("ERR: addr: 0x%X fail to communicate-2!\n", client->addr); + continue; + } + + if (0 > i2c_master_recv(client, &(_baDataBuf[0]), 1)) + { + GSE_ERR("ERR: addr: 0x%X fail to communicate-3!\n", client->addr); + continue; + } + + GSE_LOG("[%s] addr: 0x%X ok to read REG(0x3B): 0x%X\n", __FUNCTION__, client->addr, _baDataBuf[0]); + + if (MC3XXX_RETCODE_SUCCESS == mc3xxx_validate_sensor_IC(_baDataBuf[0])) + { + GSE_LOG("[%s] addr: 0x%X confirmed ok to use.\n", __FUNCTION__, client->addr); + s_bPCODE = _baDataBuf[0]; + return (MC3XXX_RETCODE_SUCCESS); + } + } + + return (MC3XXX_RETCODE_ERROR_I2C); +} + +#ifdef CONFIG_OF +static int mc3xxx_power_init(struct mc3xxx_data *data, bool on) +{ + int rc; + int vol_uv; + int enabled = 0; + + if (!on) { + if (data->vdd_enabled) { + regulator_disable(data->vdd); + data->vdd_enabled = false; + } + if (data->vio_enabled) { + regulator_disable(data->vio); + data->vio_enabled = false; + } + + regulator_set_voltage(data->vdd, 0, MC3XXX_VDD_MAX_UV); + regulator_set_voltage(data->vio, 0, MC3XXX_VIO_MAX_UV); + } else { + if (!(data->vdd)){ + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->client->dev, "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + } + vol_uv = regulator_get_voltage(data->vdd); + enabled = regulator_is_enabled(data->vdd); + dev_info(&data->client->dev, "vdd current voltate is %duv, enabled = %d ", vol_uv, enabled); + if (((vol_uv <= MC3XXX_VDD_MIN_UV) || (vol_uv >= MC3XXX_VDD_MAX_UV)) + && (regulator_count_voltages(data->vdd) > 0)) { + rc = regulator_set_voltage(data->vdd, MC3XXX_VDD_MIN_UV, + MC3XXX_VDD_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "Regulator set failed vdd rc=%d\n", + rc); + goto reg_vdd_put; + } + } + if (enabled != 1) { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + goto reg_vdd_put; + } + data->vdd_enabled = true; + } + + if (!(data->vio)){ + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->client->dev, + "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_dis; + + } + } + + vol_uv = regulator_get_voltage(data->vio); + enabled = regulator_is_enabled(data->vio); + dev_info(&data->client->dev, "vio current voltate is %duv, enabled = %d \n", vol_uv, enabled); + if (((vol_uv <= MC3XXX_VIO_MIN_UV) || (vol_uv >= MC3XXX_VIO_MAX_UV)) + && (regulator_count_voltages(data->vio) > 0)) { + rc = regulator_set_voltage(data->vio, MC3XXX_VIO_MIN_UV, + MC3XXX_VIO_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + if (enabled != 1) { + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->client->dev, + "Regulator vio enable failed rc=%d\n", rc); + goto reg_vio_put; + } + data->vio_enabled = true; + msleep(10); + } + } + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_dis: + if (data->vdd_enabled){ + regulator_disable(data->vdd); + data->vdd_enabled = false; + } +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} + +static int mc3xxx_parse_dt(struct device *dev, + struct mc3xxx_data *data) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + rc = of_property_read_u32(np, "mc,axis-map-x", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read axis-map_x\n"); + return rc; + } else { + data->axis_map_x = (u8)temp_val; + } + + rc = of_property_read_u32(np, "mc,axis-map-y", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read axis_map_y\n"); + return rc; + } else { + data->axis_map_y = (u8)temp_val; + } + + rc = of_property_read_u32(np, "mc,axis-map-z", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read axis-map-z\n"); + return rc; + } else { + data->axis_map_z = (u8)temp_val; + } + + data->negate_x = of_property_read_bool(np, "mc,negate-x"); + + data->negate_y = of_property_read_bool(np, "mc,negate-y"); + + data->negate_z = of_property_read_bool(np, "mc,negate-z"); + + return 0; +} + +static int mc3xxx_parse_gpio(struct device *dev) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + temp_val = of_get_named_gpio(np, "gpio-irq-pin", 0); + if (gpio_is_valid(temp_val)) { + rc = gpio_request(temp_val, "mc3xxx_irq"); + if (rc) { + dev_err(dev, "irq gpio request failed"); + } else + gpio_direction_input(temp_val); + } + return 0; +} +#else +static int mc3xxx_power_init(struct mc3xxx_data *data, bool on) +{ + return 0; +} +static int mc3xxx_parse_dt(struct device *dev, + struct mc3xxx_data *data) +{ + return -ENODEV; +} + +static int mc3xxx_parse_gpio(struct device *dev) +{ + return 0; +} + +#endif +//============================================================================= +static int mc3xxx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct mc3xxx_data *data = NULL; + GSENSOR_DBG(); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE |I2C_FUNC_SMBUS_BYTE_DATA |I2C_FUNC_SMBUS_WORD_DATA)) { + dev_err(&client->dev, "client not smb-i2c capable:1\n"); + ret = -EIO; + goto err_check_functionality_failed; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)){ + dev_err(&client->dev, "client not smb-i2c capable:2\n"); + ret = -EIO; + goto err_check_functionality_failed; + } + + data = kzalloc(sizeof(struct mc3xxx_data), GFP_KERNEL); + if(data == NULL) + { + ret = -ENOMEM; + goto err_alloc_data_failed; + } + + data->client = client; + ret = mc3xxx_parse_dt(&client->dev, data); + if (ret) { + dev_err(&client->dev, + "Unable to parse platfrom data err=%d\n", ret); + goto err_parse_dt; + } + + data->vdd_enabled = false; + data->vio_enabled = false; + ret = mc3xxx_power_init(data, true); + if (ret < 0) { + dev_err(&client->dev, "power init failed! err=%d", ret); + goto err_parse_dt; + } + + if (MC3XXX_RETCODE_SUCCESS != mc3xxx_i2c_auto_probe(client)) + { + dev_err(&client->dev,"fail to probe mCube sensor!\n"); + goto err_power_deinit; + } + mc3xxx_parse_gpio(&client->dev); + +#ifdef DOT_CALI + load_cali_flg = 30; +#endif + + data->mc3xxx_wq = create_singlethread_workqueue("mc3xxx_wq"); + if (!data->mc3xxx_wq) + { + ret = -ENOMEM; + goto err_create_workqueue_failed; + } + INIT_WORK(&data->work, mc3xxx_work_func); + + data->duration = SENSOR_DURATION_DEFAULT; + + i2c_set_clientdata(client, data); + + data->input_dev = input_allocate_device(); + if (!data->input_dev) { + ret = -ENOMEM; + goto exit_input_dev_alloc_failed; + } + + set_bit(EV_ABS, data->input_dev->evbit); + input_set_abs_params(data->input_dev, ABS_X, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Y, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Z, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + + data->input_dev->name = "zte_acc"; + data->input_dev->id.bustype = BUS_I2C; + data->input_dev->dev.parent = &client->dev; + + ret = input_register_device(data->input_dev); + if (ret) { + goto exit_input_register_device_failed; + } + +#ifdef DOT_CALI + MC3XXX_Reset(client); + mutex_init(&data->lock); +#endif + + mc3xxx_device.parent = &client->dev; + + ret = misc_register(&mc3xxx_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = create_sysfs_interfaces(&client->dev); + if (ret < 0) { + dev_err(&client->dev, + "ucube sysfs register failed\n"); + goto exit_sysfs_create_failed; + } + + hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->timer.function = mc3xxx_timer_func; + + printk("mc3xxx probe ok \n"); + + return 0; + +exit_sysfs_create_failed: + misc_deregister(&mc3xxx_device); +exit_misc_device_register_failed: + input_unregister_device(data->input_dev); + goto exit_input_dev_alloc_failed; +exit_input_register_device_failed: + input_free_device(data->input_dev); +exit_input_dev_alloc_failed: + destroy_workqueue(data->mc3xxx_wq); +err_create_workqueue_failed: +err_power_deinit: + mc3xxx_power_init(data, false); + regulator_put(data->vdd); + regulator_put(data->vio); +err_parse_dt: + kfree(data); +err_alloc_data_failed: +err_check_functionality_failed: + printk("mc3xxx probe failed \n"); + return ret; +} + +//============================================================================= +static int mc3xxx_remove(struct i2c_client *client) +{ + struct mc3xxx_data *data = i2c_get_clientdata(client); + + hrtimer_cancel(&data->timer); + input_unregister_device(data->input_dev); + misc_deregister(&mc3xxx_device); + remove_sysfs_interfaces(&client->dev); + destroy_workqueue(data->mc3xxx_wq); + mc3xxx_power_init(data, false); + regulator_put(data->vdd); + regulator_put(data->vio); + kfree(data); + return 0; +} + + +static ssize_t acc_info_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "0x%x\n", s_bPCODE); +} + +static struct proc_dir_entry *acc_info_proc_file; +static int __init create_acc_info_proc_file(void) +{ + if(0x0 == s_bPCODE) { + printk("not create mc3xxx proc file due to unconnected\n"); + return 0; + } + acc_info_proc_file = create_proc_entry("driver/accel", 0644, NULL); + printk("goes to create_acc_info_proc_file\n"); + if (acc_info_proc_file) { + acc_info_proc_file->read_proc = acc_info_read_proc; + } else{ + printk(KERN_INFO "proc file create failed!\n"); + } + return 0; +} + +//============================================================================= +static struct of_device_id mc3xxx_match_table[] = { + { .compatible = "mc,mc3xxx", }, + { }, +}; + +static const struct i2c_device_id mc3xxx_id[] = +{ + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, mc3xxx_id); + +static struct i2c_driver mc3xxx_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = mc3xxx_match_table, + }, + + .id_table = mc3xxx_id, + .probe = mc3xxx_probe, + .remove = mc3xxx_remove, + .suspend = mc3xxx_suspend, + .resume = mc3xxx_resume, +}; + +module_i2c_driver(mc3xxx_driver); +late_initcall(create_acc_info_proc_file); + +MODULE_DESCRIPTION("mc3xxx accelerometer driver"); +MODULE_AUTHOR("mCube-inc"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(SENSOR_DRIVER_VERSION); + diff --git a/include/linux/akm8963.h b/include/linux/akm8963.h new file mode 100644 index 000000000000..431dfdfdfa43 --- /dev/null +++ b/include/linux/akm8963.h @@ -0,0 +1,95 @@ +/* + * Definitions for akm8963 compass chip. + */ +#ifndef AKM8963_H +#define AKM8963_H + +#include + +#define AKM8963_I2C_NAME "akm8963" + +#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 AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x01, char*) +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char*) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x03, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x04, char[SENSOR_DATA_SIZE]) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x05, int[YPR_DATA_SIZE]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x06, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x07, int) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x08, long long int[AKM_NUM_SENSORS]) +#define ECS_IOCTL_GET_LAYOUT _IOR(AKMIO, 0x09, char) +#define ECS_IOCTL_GET_OUTBIT _IOR(AKMIO, 0x0B, char) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x0C) +#define ECS_IOCTL_GET_ACCEL _IOR(AKMIO, 0x30, short[3]) + +struct akm8963_platform_data { + char layout; + char outbit; + int gpio_DRDY; + int gpio_RST; +}; + +#endif + diff --git a/include/linux/bma2xx.h b/include/linux/bma2xx.h new file mode 100644 index 000000000000..9dc942bc79f7 --- /dev/null +++ b/include/linux/bma2xx.h @@ -0,0 +1,691 @@ +/******************************************************************************* +* Copyright 2013 Broadcom Corporation. All rights reserved. +* +*@file include/linux/bma250.h +* +* Unless you and Broadcom execute a separate written software license agreement +* governing use of this software, this software is licensed to you under the +* terms of the GNU General Public License version 2, available at +* http://www.gnu.org/copyleft/gpl.html (the "GPL"). +* +* Notwithstanding the above, under no circumstances may you combine this +* software in any way with any other Broadcom software provided under a license +* other than the GPL, without Broadcom's express prior written consent. +*******************************************************************************/ + +#ifndef LINUX_BMA2XXX_MODULE_H +#define LINUX_BMA2XXX_MODULE_H + +#define SENSOR_NAME "bma2xx" +#define ABSMIN -512 +#define ABSMAX 512 +#define SLOPE_THRESHOLD_VALUE 32 +#define SLOPE_DURATION_VALUE 1 +#define INTERRUPT_LATCH_MODE 13 +#define INTERRUPT_ENABLE 1 +#define INTERRUPT_DISABLE 0 +#define MAP_SLOPE_INTERRUPT 2 +#define SLOPE_X_INDEX 5 +#define SLOPE_Y_INDEX 6 +#define SLOPE_Z_INDEX 7 +#define BMA2XXX_MAX_DELAY 200 +#define BMA2XXX_CHIP_ID 3 +#define BMA2XXX_RANGE_SET 0 +#define BMA2XXX_BW_SET 4 + +#define LOW_G_INTERRUPT REL_Z +#define HIGH_G_INTERRUPT REL_HWHEEL +#define SLOP_INTERRUPT REL_DIAL +#define DOUBLE_TAP_INTERRUPT REL_WHEEL +#define SINGLE_TAP_INTERRUPT REL_MISC +#define ORIENT_INTERRUPT ABS_PRESSURE +#define FLAT_INTERRUPT ABS_DISTANCE + +#define HIGH_G_INTERRUPT_X_HAPPENED 1 +#define HIGH_G_INTERRUPT_Y_HAPPENED 2 +#define HIGH_G_INTERRUPT_Z_HAPPENED 3 +#define HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED 4 +#define HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED 5 +#define HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED 6 +#define SLOPE_INTERRUPT_X_HAPPENED 7 +#define SLOPE_INTERRUPT_Y_HAPPENED 8 +#define SLOPE_INTERRUPT_Z_HAPPENED 9 +#define SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED 10 +#define SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED 11 +#define SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED 12 +#define DOUBLE_TAP_INTERRUPT_HAPPENED 13 +#define SINGLE_TAP_INTERRUPT_HAPPENED 14 +#define UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 15 +#define UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 16 +#define UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 17 +#define UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 18 +#define DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 19 +#define DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 20 +#define DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 21 +#define DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 22 +#define FLAT_INTERRUPT_TURE_HAPPENED 23 +#define FLAT_INTERRUPT_FALSE_HAPPENED 24 +#define LOW_G_INTERRUPT_HAPPENED 25 + +#define PAD_LOWG 0 +#define PAD_HIGHG 1 +#define PAD_SLOP 2 +#define PAD_DOUBLE_TAP 3 +#define PAD_SINGLE_TAP 4 +#define PAD_ORIENT 5 +#define PAD_FLAT 6 + +#define BMA2XXX_CHIP_ID_REG 0x00 +#define BMA2XXX_VERSION_REG 0x01 +#define BMA2XXX_X_AXIS_LSB_REG 0x02 +#define BMA2XXX_X_AXIS_MSB_REG 0x03 +#define BMA2XXX_Y_AXIS_LSB_REG 0x04 +#define BMA2XXX_Y_AXIS_MSB_REG 0x05 +#define BMA2XXX_Z_AXIS_LSB_REG 0x06 +#define BMA2XXX_Z_AXIS_MSB_REG 0x07 +#define BMA2XXX_TEMP_RD_REG 0x08 +#define BMA2XXX_STATUS1_REG 0x09 +#define BMA2XXX_STATUS2_REG 0x0A +#define BMA2XXX_STATUS_TAP_SLOPE_REG 0x0B +#define BMA2XXX_STATUS_ORIENT_HIGH_REG 0x0C +#define BMA2XXX_RANGE_SEL_REG 0x0F +#define BMA2XXX_BW_SEL_REG 0x10 +#define BMA2XXX_MODE_CTRL_REG 0x11 +#define BMA2XXX_LOW_NOISE_CTRL_REG 0x12 +#define BMA2XXX_DATA_CTRL_REG 0x13 +#define BMA2XXX_RESET_REG 0x14 +#define BMA2XXX_INT_ENABLE1_REG 0x16 +#define BMA2XXX_INT_ENABLE2_REG 0x17 +#define BMA2XXX_INT1_PAD_SEL_REG 0x19 +#define BMA2XXX_INT_DATA_SEL_REG 0x1A +#define BMA2XXX_INT2_PAD_SEL_REG 0x1B +#define BMA2XXX_INT_SRC_REG 0x1E +#define BMA2XXX_INT_SET_REG 0x20 +#define BMA2XXX_INT_CTRL_REG 0x21 +#define BMA2XXX_LOW_DURN_REG 0x22 +#define BMA2XXX_LOW_THRES_REG 0x23 +#define BMA2XXX_LOW_HIGH_HYST_REG 0x24 +#define BMA2XXX_HIGH_DURN_REG 0x25 +#define BMA2XXX_HIGH_THRES_REG 0x26 +#define BMA2XXX_SLOPE_DURN_REG 0x27 +#define BMA2XXX_SLOPE_THRES_REG 0x28 +#define BMA2XXX_TAP_PARAM_REG 0x2A +#define BMA2XXX_TAP_THRES_REG 0x2B +#define BMA2XXX_ORIENT_PARAM_REG 0x2C +#define BMA2XXX_THETA_BLOCK_REG 0x2D +#define BMA2XXX_THETA_FLAT_REG 0x2E +#define BMA2XXX_FLAT_HOLD_TIME_REG 0x2F +#define BMA2XXX_STATUS_LOW_POWER_REG 0x31 +#define BMA2XXX_SELF_TEST_REG 0x32 +#define BMA2XXX_EEPROM_CTRL_REG 0x33 +#define BMA2XXX_SERIAL_CTRL_REG 0x34 +#define BMA2XXX_CTRL_UNLOCK_REG 0x35 +#define BMA2XXX_OFFSET_CTRL_REG 0x36 +#define BMA2XXX_OFFSET_PARAMS_REG 0x37 +#define BMA2XXX_OFFSET_FILT_X_REG 0x38 +#define BMA2XXX_OFFSET_FILT_Y_REG 0x39 +#define BMA2XXX_OFFSET_FILT_Z_REG 0x3A +#define BMA2XXX_OFFSET_UNFILT_X_REG 0x3B +#define BMA2XXX_OFFSET_UNFILT_Y_REG 0x3C +#define BMA2XXX_OFFSET_UNFILT_Z_REG 0x3D +#define BMA2XXX_SPARE_0_REG 0x3E +#define BMA2XXX_SPARE_1_REG 0x3F + +#define BMA2XXX_ACC_X_LSB__POS 6 +#define BMA2XXX_ACC_X_LSB__LEN 2 +#define BMA2XXX_ACC_X_LSB__MSK 0xC0 +#define BMA2XXX_ACC_X_LSB__REG BMA2XXX_X_AXIS_LSB_REG + +#define BMA2XXX_ACC_X_MSB__POS 0 +#define BMA2XXX_ACC_X_MSB__LEN 8 +#define BMA2XXX_ACC_X_MSB__MSK 0xFF +#define BMA2XXX_ACC_X_MSB__REG BMA2XXX_X_AXIS_MSB_REG + +#define BMA2XXX_ACC_Y_LSB__POS 6 +#define BMA2XXX_ACC_Y_LSB__LEN 2 +#define BMA2XXX_ACC_Y_LSB__MSK 0xC0 +#define BMA2XXX_ACC_Y_LSB__REG BMA2XXX_Y_AXIS_LSB_REG + +#define BMA2XXX_ACC_Y_MSB__POS 0 +#define BMA2XXX_ACC_Y_MSB__LEN 8 +#define BMA2XXX_ACC_Y_MSB__MSK 0xFF +#define BMA2XXX_ACC_Y_MSB__REG BMA2XXX_Y_AXIS_MSB_REG + +#define BMA2XXX_ACC_Z_LSB__POS 6 +#define BMA2XXX_ACC_Z_LSB__LEN 2 +#define BMA2XXX_ACC_Z_LSB__MSK 0xC0 +#define BMA2XXX_ACC_Z_LSB__REG BMA2XXX_Z_AXIS_LSB_REG + +#define BMA2XXX_ACC_Z_MSB__POS 0 +#define BMA2XXX_ACC_Z_MSB__LEN 8 +#define BMA2XXX_ACC_Z_MSB__MSK 0xFF +#define BMA2XXX_ACC_Z_MSB__REG BMA2XXX_Z_AXIS_MSB_REG + +#define BMA2XXX_RANGE_SEL__POS 0 +#define BMA2XXX_RANGE_SEL__LEN 4 +#define BMA2XXX_RANGE_SEL__MSK 0x0F +#define BMA2XXX_RANGE_SEL__REG BMA2XXX_RANGE_SEL_REG + +#define BMA2XXX_BANDWIDTH__POS 0 +#define BMA2XXX_BANDWIDTH__LEN 5 +#define BMA2XXX_BANDWIDTH__MSK 0x1F +#define BMA2XXX_BANDWIDTH__REG BMA2XXX_BW_SEL_REG + +#define BMA2XXX_EN_LOW_POWER__POS 6 +#define BMA2XXX_EN_LOW_POWER__LEN 1 +#define BMA2XXX_EN_LOW_POWER__MSK 0x40 +#define BMA2XXX_EN_LOW_POWER__REG BMA2XXX_MODE_CTRL_REG + +#define BMA2XXX_EN_SUSPEND__POS 7 +#define BMA2XXX_EN_SUSPEND__LEN 1 +#define BMA2XXX_EN_SUSPEND__MSK 0x80 +#define BMA2XXX_EN_SUSPEND__REG BMA2XXX_MODE_CTRL_REG + +#define BMA2XXX_INT_MODE_SEL__POS 0 +#define BMA2XXX_INT_MODE_SEL__LEN 4 +#define BMA2XXX_INT_MODE_SEL__MSK 0x0F +#define BMA2XXX_INT_MODE_SEL__REG BMA2XXX_INT_CTRL_REG + +#define BMA2XXX_LOWG_INT_S__POS 0 +#define BMA2XXX_LOWG_INT_S__LEN 1 +#define BMA2XXX_LOWG_INT_S__MSK 0x01 +#define BMA2XXX_LOWG_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_HIGHG_INT_S__POS 1 +#define BMA2XXX_HIGHG_INT_S__LEN 1 +#define BMA2XXX_HIGHG_INT_S__MSK 0x02 +#define BMA2XXX_HIGHG_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_SLOPE_INT_S__POS 2 +#define BMA2XXX_SLOPE_INT_S__LEN 1 +#define BMA2XXX_SLOPE_INT_S__MSK 0x04 +#define BMA2XXX_SLOPE_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_DOUBLE_TAP_INT_S__POS 4 +#define BMA2XXX_DOUBLE_TAP_INT_S__LEN 1 +#define BMA2XXX_DOUBLE_TAP_INT_S__MSK 0x10 +#define BMA2XXX_DOUBLE_TAP_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_SINGLE_TAP_INT_S__POS 5 +#define BMA2XXX_SINGLE_TAP_INT_S__LEN 1 +#define BMA2XXX_SINGLE_TAP_INT_S__MSK 0x20 +#define BMA2XXX_SINGLE_TAP_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_ORIENT_INT_S__POS 6 +#define BMA2XXX_ORIENT_INT_S__LEN 1 +#define BMA2XXX_ORIENT_INT_S__MSK 0x40 +#define BMA2XXX_ORIENT_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_FLAT_INT_S__POS 7 +#define BMA2XXX_FLAT_INT_S__LEN 1 +#define BMA2XXX_FLAT_INT_S__MSK 0x80 +#define BMA2XXX_FLAT_INT_S__REG BMA2XXX_STATUS1_REG + +#define BMA2XXX_DATA_INT_S__POS 7 +#define BMA2XXX_DATA_INT_S__LEN 1 +#define BMA2XXX_DATA_INT_S__MSK 0x80 +#define BMA2XXX_DATA_INT_S__REG BMA2XXX_STATUS2_REG + +#define BMA2XXX_SLOPE_FIRST_X__POS 0 +#define BMA2XXX_SLOPE_FIRST_X__LEN 1 +#define BMA2XXX_SLOPE_FIRST_X__MSK 0x01 +#define BMA2XXX_SLOPE_FIRST_X__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_SLOPE_FIRST_Y__POS 1 +#define BMA2XXX_SLOPE_FIRST_Y__LEN 1 +#define BMA2XXX_SLOPE_FIRST_Y__MSK 0x02 +#define BMA2XXX_SLOPE_FIRST_Y__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_SLOPE_FIRST_Z__POS 2 +#define BMA2XXX_SLOPE_FIRST_Z__LEN 1 +#define BMA2XXX_SLOPE_FIRST_Z__MSK 0x04 +#define BMA2XXX_SLOPE_FIRST_Z__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_SLOPE_SIGN_S__POS 3 +#define BMA2XXX_SLOPE_SIGN_S__LEN 1 +#define BMA2XXX_SLOPE_SIGN_S__MSK 0x08 +#define BMA2XXX_SLOPE_SIGN_S__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_TAP_FIRST_X__POS 4 +#define BMA2XXX_TAP_FIRST_X__LEN 1 +#define BMA2XXX_TAP_FIRST_X__MSK 0x10 +#define BMA2XXX_TAP_FIRST_X__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_TAP_FIRST_Y__POS 5 +#define BMA2XXX_TAP_FIRST_Y__LEN 1 +#define BMA2XXX_TAP_FIRST_Y__MSK 0x20 +#define BMA2XXX_TAP_FIRST_Y__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_TAP_FIRST_Z__POS 6 +#define BMA2XXX_TAP_FIRST_Z__LEN 1 +#define BMA2XXX_TAP_FIRST_Z__MSK 0x40 +#define BMA2XXX_TAP_FIRST_Z__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_TAP_FIRST_XYZ__POS 4 +#define BMA2XXX_TAP_FIRST_XYZ__LEN 3 +#define BMA2XXX_TAP_FIRST_XYZ__MSK 0x70 +#define BMA2XXX_TAP_FIRST_XYZ__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_TAP_SIGN_S__POS 7 +#define BMA2XXX_TAP_SIGN_S__LEN 1 +#define BMA2XXX_TAP_SIGN_S__MSK 0x80 +#define BMA2XXX_TAP_SIGN_S__REG BMA2XXX_STATUS_TAP_SLOPE_REG + +#define BMA2XXX_HIGHG_FIRST_X__POS 0 +#define BMA2XXX_HIGHG_FIRST_X__LEN 1 +#define BMA2XXX_HIGHG_FIRST_X__MSK 0x01 +#define BMA2XXX_HIGHG_FIRST_X__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_HIGHG_FIRST_Y__POS 1 +#define BMA2XXX_HIGHG_FIRST_Y__LEN 1 +#define BMA2XXX_HIGHG_FIRST_Y__MSK 0x02 +#define BMA2XXX_HIGHG_FIRST_Y__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_HIGHG_FIRST_Z__POS 2 +#define BMA2XXX_HIGHG_FIRST_Z__LEN 1 +#define BMA2XXX_HIGHG_FIRST_Z__MSK 0x04 +#define BMA2XXX_HIGHG_FIRST_Z__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_HIGHG_SIGN_S__POS 3 +#define BMA2XXX_HIGHG_SIGN_S__LEN 1 +#define BMA2XXX_HIGHG_SIGN_S__MSK 0x08 +#define BMA2XXX_HIGHG_SIGN_S__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_ORIENT_S__POS 4 +#define BMA2XXX_ORIENT_S__LEN 3 +#define BMA2XXX_ORIENT_S__MSK 0x70 +#define BMA2XXX_ORIENT_S__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_FLAT_S__POS 7 +#define BMA2XXX_FLAT_S__LEN 1 +#define BMA2XXX_FLAT_S__MSK 0x80 +#define BMA2XXX_FLAT_S__REG BMA2XXX_STATUS_ORIENT_HIGH_REG + +#define BMA2XXX_EN_SLOPE_X_INT__POS 0 +#define BMA2XXX_EN_SLOPE_X_INT__LEN 1 +#define BMA2XXX_EN_SLOPE_X_INT__MSK 0x01 +#define BMA2XXX_EN_SLOPE_X_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_SLOPE_Y_INT__POS 1 +#define BMA2XXX_EN_SLOPE_Y_INT__LEN 1 +#define BMA2XXX_EN_SLOPE_Y_INT__MSK 0x02 +#define BMA2XXX_EN_SLOPE_Y_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_SLOPE_Z_INT__POS 2 +#define BMA2XXX_EN_SLOPE_Z_INT__LEN 1 +#define BMA2XXX_EN_SLOPE_Z_INT__MSK 0x04 +#define BMA2XXX_EN_SLOPE_Z_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_SLOPE_XYZ_INT__POS 0 +#define BMA2XXX_EN_SLOPE_XYZ_INT__LEN 3 +#define BMA2XXX_EN_SLOPE_XYZ_INT__MSK 0x07 +#define BMA2XXX_EN_SLOPE_XYZ_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_DOUBLE_TAP_INT__POS 4 +#define BMA2XXX_EN_DOUBLE_TAP_INT__LEN 1 +#define BMA2XXX_EN_DOUBLE_TAP_INT__MSK 0x10 +#define BMA2XXX_EN_DOUBLE_TAP_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_SINGLE_TAP_INT__POS 5 +#define BMA2XXX_EN_SINGLE_TAP_INT__LEN 1 +#define BMA2XXX_EN_SINGLE_TAP_INT__MSK 0x20 +#define BMA2XXX_EN_SINGLE_TAP_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_ORIENT_INT__POS 6 +#define BMA2XXX_EN_ORIENT_INT__LEN 1 +#define BMA2XXX_EN_ORIENT_INT__MSK 0x40 +#define BMA2XXX_EN_ORIENT_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_FLAT_INT__POS 7 +#define BMA2XXX_EN_FLAT_INT__LEN 1 +#define BMA2XXX_EN_FLAT_INT__MSK 0x80 +#define BMA2XXX_EN_FLAT_INT__REG BMA2XXX_INT_ENABLE1_REG + +#define BMA2XXX_EN_HIGHG_X_INT__POS 0 +#define BMA2XXX_EN_HIGHG_X_INT__LEN 1 +#define BMA2XXX_EN_HIGHG_X_INT__MSK 0x01 +#define BMA2XXX_EN_HIGHG_X_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_HIGHG_Y_INT__POS 1 +#define BMA2XXX_EN_HIGHG_Y_INT__LEN 1 +#define BMA2XXX_EN_HIGHG_Y_INT__MSK 0x02 +#define BMA2XXX_EN_HIGHG_Y_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_HIGHG_Z_INT__POS 2 +#define BMA2XXX_EN_HIGHG_Z_INT__LEN 1 +#define BMA2XXX_EN_HIGHG_Z_INT__MSK 0x04 +#define BMA2XXX_EN_HIGHG_Z_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_HIGHG_XYZ_INT__POS 2 +#define BMA2XXX_EN_HIGHG_XYZ_INT__LEN 1 +#define BMA2XXX_EN_HIGHG_XYZ_INT__MSK 0x04 +#define BMA2XXX_EN_HIGHG_XYZ_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_LOWG_INT__POS 3 +#define BMA2XXX_EN_LOWG_INT__LEN 1 +#define BMA2XXX_EN_LOWG_INT__MSK 0x08 +#define BMA2XXX_EN_LOWG_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_NEW_DATA_INT__POS 4 +#define BMA2XXX_EN_NEW_DATA_INT__LEN 1 +#define BMA2XXX_EN_NEW_DATA_INT__MSK 0x10 +#define BMA2XXX_EN_NEW_DATA_INT__REG BMA2XXX_INT_ENABLE2_REG + +#define BMA2XXX_EN_INT1_PAD_LOWG__POS 0 +#define BMA2XXX_EN_INT1_PAD_LOWG__LEN 1 +#define BMA2XXX_EN_INT1_PAD_LOWG__MSK 0x01 +#define BMA2XXX_EN_INT1_PAD_LOWG__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_HIGHG__POS 1 +#define BMA2XXX_EN_INT1_PAD_HIGHG__LEN 1 +#define BMA2XXX_EN_INT1_PAD_HIGHG__MSK 0x02 +#define BMA2XXX_EN_INT1_PAD_HIGHG__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_SLOPE__POS 2 +#define BMA2XXX_EN_INT1_PAD_SLOPE__LEN 1 +#define BMA2XXX_EN_INT1_PAD_SLOPE__MSK 0x04 +#define BMA2XXX_EN_INT1_PAD_SLOPE__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_DB_TAP__POS 4 +#define BMA2XXX_EN_INT1_PAD_DB_TAP__LEN 1 +#define BMA2XXX_EN_INT1_PAD_DB_TAP__MSK 0x10 +#define BMA2XXX_EN_INT1_PAD_DB_TAP__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_SNG_TAP__POS 5 +#define BMA2XXX_EN_INT1_PAD_SNG_TAP__LEN 1 +#define BMA2XXX_EN_INT1_PAD_SNG_TAP__MSK 0x20 +#define BMA2XXX_EN_INT1_PAD_SNG_TAP__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_ORIENT__POS 6 +#define BMA2XXX_EN_INT1_PAD_ORIENT__LEN 1 +#define BMA2XXX_EN_INT1_PAD_ORIENT__MSK 0x40 +#define BMA2XXX_EN_INT1_PAD_ORIENT__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_FLAT__POS 7 +#define BMA2XXX_EN_INT1_PAD_FLAT__LEN 1 +#define BMA2XXX_EN_INT1_PAD_FLAT__MSK 0x80 +#define BMA2XXX_EN_INT1_PAD_FLAT__REG BMA2XXX_INT1_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_LOWG__POS 0 +#define BMA2XXX_EN_INT2_PAD_LOWG__LEN 1 +#define BMA2XXX_EN_INT2_PAD_LOWG__MSK 0x01 +#define BMA2XXX_EN_INT2_PAD_LOWG__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_HIGHG__POS 1 +#define BMA2XXX_EN_INT2_PAD_HIGHG__LEN 1 +#define BMA2XXX_EN_INT2_PAD_HIGHG__MSK 0x02 +#define BMA2XXX_EN_INT2_PAD_HIGHG__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_SLOPE__POS 2 +#define BMA2XXX_EN_INT2_PAD_SLOPE__LEN 1 +#define BMA2XXX_EN_INT2_PAD_SLOPE__MSK 0x04 +#define BMA2XXX_EN_INT2_PAD_SLOPE__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_DB_TAP__POS 4 +#define BMA2XXX_EN_INT2_PAD_DB_TAP__LEN 1 +#define BMA2XXX_EN_INT2_PAD_DB_TAP__MSK 0x10 +#define BMA2XXX_EN_INT2_PAD_DB_TAP__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_SNG_TAP__POS 5 +#define BMA2XXX_EN_INT2_PAD_SNG_TAP__LEN 1 +#define BMA2XXX_EN_INT2_PAD_SNG_TAP__MSK 0x20 +#define BMA2XXX_EN_INT2_PAD_SNG_TAP__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_ORIENT__POS 6 +#define BMA2XXX_EN_INT2_PAD_ORIENT__LEN 1 +#define BMA2XXX_EN_INT2_PAD_ORIENT__MSK 0x40 +#define BMA2XXX_EN_INT2_PAD_ORIENT__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_FLAT__POS 7 +#define BMA2XXX_EN_INT2_PAD_FLAT__LEN 1 +#define BMA2XXX_EN_INT2_PAD_FLAT__MSK 0x80 +#define BMA2XXX_EN_INT2_PAD_FLAT__REG BMA2XXX_INT2_PAD_SEL_REG + +#define BMA2XXX_EN_INT1_PAD_NEWDATA__POS 0 +#define BMA2XXX_EN_INT1_PAD_NEWDATA__LEN 1 +#define BMA2XXX_EN_INT1_PAD_NEWDATA__MSK 0x01 +#define BMA2XXX_EN_INT1_PAD_NEWDATA__REG BMA2XXX_INT_DATA_SEL_REG + +#define BMA2XXX_EN_INT2_PAD_NEWDATA__POS 7 +#define BMA2XXX_EN_INT2_PAD_NEWDATA__LEN 1 +#define BMA2XXX_EN_INT2_PAD_NEWDATA__MSK 0x80 +#define BMA2XXX_EN_INT2_PAD_NEWDATA__REG BMA2XXX_INT_DATA_SEL_REG + +#define BMA2XXX_UNFILT_INT_SRC_LOWG__POS 0 +#define BMA2XXX_UNFILT_INT_SRC_LOWG__LEN 1 +#define BMA2XXX_UNFILT_INT_SRC_LOWG__MSK 0x01 +#define BMA2XXX_UNFILT_INT_SRC_LOWG__REG BMA2XXX_INT_SRC_REG + +#define BMA2XXX_UNFILT_INT_SRC_HIGHG__POS 1 +#define BMA2XXX_UNFILT_INT_SRC_HIGHG__LEN 1 +#define BMA2XXX_UNFILT_INT_SRC_HIGHG__MSK 0x02 +#define BMA2XXX_UNFILT_INT_SRC_HIGHG__REG BMA2XXX_INT_SRC_REG + +#define BMA2XXX_UNFILT_INT_SRC_SLOPE__POS 2 +#define BMA2XXX_UNFILT_INT_SRC_SLOPE__LEN 1 +#define BMA2XXX_UNFILT_INT_SRC_SLOPE__MSK 0x04 +#define BMA2XXX_UNFILT_INT_SRC_SLOPE__REG BMA2XXX_INT_SRC_REG + +#define BMA2XXX_UNFILT_INT_SRC_TAP__POS 4 +#define BMA2XXX_UNFILT_INT_SRC_TAP__LEN 1 +#define BMA2XXX_UNFILT_INT_SRC_TAP__MSK 0x10 +#define BMA2XXX_UNFILT_INT_SRC_TAP__REG BMA2XXX_INT_SRC_REG + +#define BMA2XXX_UNFILT_INT_SRC_DATA__POS 5 +#define BMA2XXX_UNFILT_INT_SRC_DATA__LEN 1 +#define BMA2XXX_UNFILT_INT_SRC_DATA__MSK 0x20 +#define BMA2XXX_UNFILT_INT_SRC_DATA__REG BMA2XXX_INT_SRC_REG + +#define BMA2XXX_INT1_PAD_ACTIVE_LEVEL__POS 0 +#define BMA2XXX_INT1_PAD_ACTIVE_LEVEL__LEN 1 +#define BMA2XXX_INT1_PAD_ACTIVE_LEVEL__MSK 0x01 +#define BMA2XXX_INT1_PAD_ACTIVE_LEVEL__REG BMA2XXX_INT_SET_REG + +#define BMA2XXX_INT2_PAD_ACTIVE_LEVEL__POS 2 +#define BMA2XXX_INT2_PAD_ACTIVE_LEVEL__LEN 1 +#define BMA2XXX_INT2_PAD_ACTIVE_LEVEL__MSK 0x04 +#define BMA2XXX_INT2_PAD_ACTIVE_LEVEL__REG BMA2XXX_INT_SET_REG + +#define BMA2XXX_INT1_PAD_OUTPUT_TYPE__POS 1 +#define BMA2XXX_INT1_PAD_OUTPUT_TYPE__LEN 1 +#define BMA2XXX_INT1_PAD_OUTPUT_TYPE__MSK 0x02 +#define BMA2XXX_INT1_PAD_OUTPUT_TYPE__REG BMA2XXX_INT_SET_REG + +#define BMA2XXX_INT2_PAD_OUTPUT_TYPE__POS 3 +#define BMA2XXX_INT2_PAD_OUTPUT_TYPE__LEN 1 +#define BMA2XXX_INT2_PAD_OUTPUT_TYPE__MSK 0x08 +#define BMA2XXX_INT2_PAD_OUTPUT_TYPE__REG BMA2XXX_INT_SET_REG + +#define BMA2XXX_INT_MODE_SEL__POS 0 +#define BMA2XXX_INT_MODE_SEL__LEN 4 +#define BMA2XXX_INT_MODE_SEL__MSK 0x0F +#define BMA2XXX_INT_MODE_SEL__REG BMA2XXX_INT_CTRL_REG + +#define BMA2XXX_INT_RESET_LATCHED__POS 7 +#define BMA2XXX_INT_RESET_LATCHED__LEN 1 +#define BMA2XXX_INT_RESET_LATCHED__MSK 0x80 +#define BMA2XXX_INT_RESET_LATCHED__REG BMA2XXX_INT_CTRL_REG + +#define BMA2XXX_LOWG_DUR__POS 0 +#define BMA2XXX_LOWG_DUR__LEN 8 +#define BMA2XXX_LOWG_DUR__MSK 0xFF +#define BMA2XXX_LOWG_DUR__REG BMA2XXX_LOW_DURN_REG + +#define BMA2XXX_LOWG_THRES__POS 0 +#define BMA2XXX_LOWG_THRES__LEN 8 +#define BMA2XXX_LOWG_THRES__MSK 0xFF +#define BMA2XXX_LOWG_THRES__REG BMA2XXX_LOW_THRES_REG + +#define BMA2XXX_LOWG_HYST__POS 0 +#define BMA2XXX_LOWG_HYST__LEN 2 +#define BMA2XXX_LOWG_HYST__MSK 0x03 +#define BMA2XXX_LOWG_HYST__REG BMA2XXX_LOW_HIGH_HYST_REG + +#define BMA2XXX_LOWG_INT_MODE__POS 2 +#define BMA2XXX_LOWG_INT_MODE__LEN 1 +#define BMA2XXX_LOWG_INT_MODE__MSK 0x04 +#define BMA2XXX_LOWG_INT_MODE__REG BMA2XXX_LOW_HIGH_HYST_REG + +#define BMA2XXX_HIGHG_DUR__POS 0 +#define BMA2XXX_HIGHG_DUR__LEN 8 +#define BMA2XXX_HIGHG_DUR__MSK 0xFF +#define BMA2XXX_HIGHG_DUR__REG BMA2XXX_HIGH_DURN_REG + +#define BMA2XXX_HIGHG_THRES__POS 0 +#define BMA2XXX_HIGHG_THRES__LEN 8 +#define BMA2XXX_HIGHG_THRES__MSK 0xFF +#define BMA2XXX_HIGHG_THRES__REG BMA2XXX_HIGH_THRES_REG + +#define BMA2XXX_HIGHG_HYST__POS 6 +#define BMA2XXX_HIGHG_HYST__LEN 2 +#define BMA2XXX_HIGHG_HYST__MSK 0xC0 +#define BMA2XXX_HIGHG_HYST__REG BMA2XXX_LOW_HIGH_HYST_REG + +#define BMA2XXX_SLOPE_DUR__POS 0 +#define BMA2XXX_SLOPE_DUR__LEN 2 +#define BMA2XXX_SLOPE_DUR__MSK 0x03 +#define BMA2XXX_SLOPE_DUR__REG BMA2XXX_SLOPE_DURN_REG + +#define BMA2XXX_SLOPE_THRES__POS 0 +#define BMA2XXX_SLOPE_THRES__LEN 8 +#define BMA2XXX_SLOPE_THRES__MSK 0xFF +#define BMA2XXX_SLOPE_THRES__REG BMA2XXX_SLOPE_THRES_REG + +#define BMA2XXX_TAP_DUR__POS 0 +#define BMA2XXX_TAP_DUR__LEN 3 +#define BMA2XXX_TAP_DUR__MSK 0x07 +#define BMA2XXX_TAP_DUR__REG BMA2XXX_TAP_PARAM_REG + +#define BMA2XXX_TAP_SHOCK_DURN__POS 6 +#define BMA2XXX_TAP_SHOCK_DURN__LEN 1 +#define BMA2XXX_TAP_SHOCK_DURN__MSK 0x40 +#define BMA2XXX_TAP_SHOCK_DURN__REG BMA2XXX_TAP_PARAM_REG + +#define BMA2XXX_TAP_QUIET_DURN__POS 7 +#define BMA2XXX_TAP_QUIET_DURN__LEN 1 +#define BMA2XXX_TAP_QUIET_DURN__MSK 0x80 +#define BMA2XXX_TAP_QUIET_DURN__REG BMA2XXX_TAP_PARAM_REG + +#define BMA2XXX_TAP_THRES__POS 0 +#define BMA2XXX_TAP_THRES__LEN 5 +#define BMA2XXX_TAP_THRES__MSK 0x1F +#define BMA2XXX_TAP_THRES__REG BMA2XXX_TAP_THRES_REG + +#define BMA2XXX_TAP_SAMPLES__POS 6 +#define BMA2XXX_TAP_SAMPLES__LEN 2 +#define BMA2XXX_TAP_SAMPLES__MSK 0xC0 +#define BMA2XXX_TAP_SAMPLES__REG BMA2XXX_TAP_THRES_REG + +#define BMA2XXX_ORIENT_MODE__POS 0 +#define BMA2XXX_ORIENT_MODE__LEN 2 +#define BMA2XXX_ORIENT_MODE__MSK 0x03 +#define BMA2XXX_ORIENT_MODE__REG BMA2XXX_ORIENT_PARAM_REG + +#define BMA2XXX_ORIENT_BLOCK__POS 2 +#define BMA2XXX_ORIENT_BLOCK__LEN 2 +#define BMA2XXX_ORIENT_BLOCK__MSK 0x0C +#define BMA2XXX_ORIENT_BLOCK__REG BMA2XXX_ORIENT_PARAM_REG + +#define BMA2XXX_ORIENT_HYST__POS 4 +#define BMA2XXX_ORIENT_HYST__LEN 3 +#define BMA2XXX_ORIENT_HYST__MSK 0x70 +#define BMA2XXX_ORIENT_HYST__REG BMA2XXX_ORIENT_PARAM_REG + +#define BMA2XXX_ORIENT_AXIS__POS 7 +#define BMA2XXX_ORIENT_AXIS__LEN 1 +#define BMA2XXX_ORIENT_AXIS__MSK 0x80 +#define BMA2XXX_ORIENT_AXIS__REG BMA2XXX_THETA_BLOCK_REG + +#define BMA2XXX_THETA_BLOCK__POS 0 +#define BMA2XXX_THETA_BLOCK__LEN 6 +#define BMA2XXX_THETA_BLOCK__MSK 0x3F +#define BMA2XXX_THETA_BLOCK__REG BMA2XXX_THETA_BLOCK_REG + +#define BMA2XXX_THETA_FLAT__POS 0 +#define BMA2XXX_THETA_FLAT__LEN 6 +#define BMA2XXX_THETA_FLAT__MSK 0x3F +#define BMA2XXX_THETA_FLAT__REG BMA2XXX_THETA_FLAT_REG + +#define BMA2XXX_FLAT_HOLD_TIME__POS 4 +#define BMA2XXX_FLAT_HOLD_TIME__LEN 2 +#define BMA2XXX_FLAT_HOLD_TIME__MSK 0x30 +#define BMA2XXX_FLAT_HOLD_TIME__REG BMA2XXX_FLAT_HOLD_TIME_REG + +#define BMA2XXX_EN_SELF_TEST__POS 0 +#define BMA2XXX_EN_SELF_TEST__LEN 2 +#define BMA2XXX_EN_SELF_TEST__MSK 0x03 +#define BMA2XXX_EN_SELF_TEST__REG BMA2XXX_SELF_TEST_REG + +#define BMA2XXX_NEG_SELF_TEST__POS 2 +#define BMA2XXX_NEG_SELF_TEST__LEN 1 +#define BMA2XXX_NEG_SELF_TEST__MSK 0x04 +#define BMA2XXX_NEG_SELF_TEST__REG BMA2XXX_SELF_TEST_REG + +#define BMA2XXX_LOW_POWER_MODE_S__POS 0 +#define BMA2XXX_LOW_POWER_MODE_S__LEN 1 +#define BMA2XXX_LOW_POWER_MODE_S__MSK 0x01 +#define BMA2XXX_LOW_POWER_MODE_S__REG BMA2XXX_STATUS_LOW_POWER_REG + +#define BMA2XXX_EN_FAST_COMP__POS 5 +#define BMA2XXX_EN_FAST_COMP__LEN 2 +#define BMA2XXX_EN_FAST_COMP__MSK 0x60 +#define BMA2XXX_EN_FAST_COMP__REG BMA2XXX_OFFSET_CTRL_REG + +#define BMA2XXX_FAST_COMP_RDY_S__POS 4 +#define BMA2XXX_FAST_COMP_RDY_S__LEN 1 +#define BMA2XXX_FAST_COMP_RDY_S__MSK 0x10 +#define BMA2XXX_FAST_COMP_RDY_S__REG BMA2XXX_OFFSET_CTRL_REG + +#define BMA2XXX_COMP_TARGET_OFFSET_X__POS 1 +#define BMA2XXX_COMP_TARGET_OFFSET_X__LEN 2 +#define BMA2XXX_COMP_TARGET_OFFSET_X__MSK 0x06 +#define BMA2XXX_COMP_TARGET_OFFSET_X__REG BMA2XXX_OFFSET_PARAMS_REG + +#define BMA2XXX_COMP_TARGET_OFFSET_Y__POS 3 +#define BMA2XXX_COMP_TARGET_OFFSET_Y__LEN 2 +#define BMA2XXX_COMP_TARGET_OFFSET_Y__MSK 0x18 +#define BMA2XXX_COMP_TARGET_OFFSET_Y__REG BMA2XXX_OFFSET_PARAMS_REG + +#define BMA2XXX_COMP_TARGET_OFFSET_Z__POS 5 +#define BMA2XXX_COMP_TARGET_OFFSET_Z__LEN 2 +#define BMA2XXX_COMP_TARGET_OFFSET_Z__MSK 0x60 +#define BMA2XXX_COMP_TARGET_OFFSET_Z__REG BMA2XXX_OFFSET_PARAMS_REG + +#define BMA2XXX_RANGE_2G 0 +#define BMA2XXX_RANGE_4G 1 +#define BMA2XXX_RANGE_8G 2 +#define BMA2XXX_RANGE_16G 3 + +#define BMA2XXX_BW_7_81HZ 0x08 +#define BMA2XXX_BW_15_63HZ 0x09 +#define BMA2XXX_BW_31_25HZ 0x0A +#define BMA2XXX_BW_62_50HZ 0x0B +#define BMA2XXX_BW_125HZ 0x0C +#define BMA2XXX_BW_250HZ 0x0D +#define BMA2XXX_BW_500HZ 0x0E +#define BMA2XXX_BW_1000HZ 0x0F +#define BMA2XXX_MODE_NORMAL 0 +#define BMA2XXX_MODE_LOWPOWER 1 +#define BMA2XXX_MODE_SUSPEND 2 + +#define BMA2XX_VDD_MIN_UV 2700000 +#define BMA2XX_VDD_MAX_UV 3300000 +#define BMA2XX_VIO_MIN_UV 1700000 +#define BMA2XX_VIO_MAX_UV 1950000 + +enum bma_orientation { + BMA_ORI_100_010_001 = 0, + BMA_ORI_010_100_001, + BMA_ORI_f00_010_001, + BMA_ORI_f00_0f0_001, + BMA_ORI_100_0f0_001 = 4, + BMA_ORI_100_010_00f, + BMA_ORI_010_100_00f, + BMA_ORI_f00_010_00f, + BMA_ORI_f00_0f0_00f = 8, + BMA_ORI_100_0f0_00f, + BMA_ORI_010_f00_00f, + BMA_ORI_0f0_100_00f, + BMA_ORI_0f0_100_001, +}; +#endif From 80cc0461514a62e9e4c6338f59ff7c57cf49f8e8 Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Tue, 24 Nov 2015 21:39:30 +1030 Subject: [PATCH 2/6] arm: DT: Import DSI-ili9488 panel. Support the ZTE T792 (Telstra Rush). --- .../dts/dsi-panel-ili9488-hvga-video.dtsi | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 arch/arm/boot/dts/dsi-panel-ili9488-hvga-video.dtsi diff --git a/arch/arm/boot/dts/dsi-panel-ili9488-hvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-ili9488-hvga-video.dtsi new file mode 100644 index 000000000000..853aae250e03 --- /dev/null +++ b/arch/arm/boot/dts/dsi-panel-ili9488-hvga-video.dtsi @@ -0,0 +1,93 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_ili9488_hvga_vid: qcom,mdss_dsi_ili9488_hvga_video { + qcom,mdss-dsi-panel-name = "ili9488 hvga video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,cont-splash-enabled = <1>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <320>; + qcom,mdss-dsi-panel-height = <480>; + qcom,mdss-dsi-h-front-porch = <20>;//80 + qcom,mdss-dsi-h-back-porch = <8>;//80 + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>;//5PCLK + qcom,mdss-dsi-v-front-porch = <15>;//5 + qcom,mdss-dsi-v-pulse-width = <2>;//5 + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ +29 01 00 00 00 00 10 + E0 00 08 12 0d 1b 0e 38 87 47 08 0E 0A 19 1b 0F +29 01 00 00 00 00 10 + E1 00 13 18 03 0f 05 2a 24 3b 02 06 03 33 33 0F +29 01 00 00 00 00 03 + C0 10 10 +29 01 00 00 00 00 02 + C1 41 +29 01 00 00 00 00 04 + C5 00 30 80 +29 01 00 00 00 00 02 + 36 08 +29 01 00 00 00 00 02 + 3A 66 +29 01 00 00 00 00 02 + B4 02 +29 01 00 00 00 00 03 + B6 02 22 +29 01 00 00 00 00 02 + E9 00 +29 01 00 00 00 00 05 + F7 A9 51 2C 82 +05 01 00 00 96 00 02 + 11 00 +05 01 00 00 1E 00 02 + 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 1E 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; //non_burst_sync_event + qcom,mdss-dsi-lane-map = "lane_map_1032"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-panel-timings = [54 10 0a 00 30 35 0f 14 12 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x1f>; //04 + qcom,mdss-dsi-t-clk-pre = <0x2b>; //1B + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + + }; +}; From f16fc19dd315e7545d7febe0d0e262b104a892b7 Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Wed, 25 Nov 2015 12:21:50 +1030 Subject: [PATCH 3/6] arm: msm: msm8610: Add a few extra clocks from the t792 --- arch/arm/mach-msm/clock-8610.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c index b0948eb0c5f5..d082876e6a49 100644 --- a/arch/arm/mach-msm/clock-8610.c +++ b/arch/arm/mach-msm/clock-8610.c @@ -3032,6 +3032,8 @@ static struct clk_lookup msm_clocks_8610[] = { CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007d"), CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"), CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0076"), //GC2235 + CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0078"), + CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007a"), CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"), CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"), CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"), @@ -3040,6 +3042,8 @@ static struct clk_lookup msm_clocks_8610[] = { CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"), CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"), CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0076"), //GC2235 + CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0078"), + CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007a"), CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"), CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"), CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006a"), From 584a459fc255c2ef282c44fd7f3992a7fb7c25ee Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Wed, 25 Nov 2015 12:27:20 +1030 Subject: [PATCH 4/6] arm: DT: Actually include the ili9488-hvga panel. --- arch/arm/boot/dts/msm8610-mdss-panels.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/msm8610-mdss-panels.dtsi b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi index e982f856d983..6b5c6c9029c3 100644 --- a/arch/arm/boot/dts/msm8610-mdss-panels.dtsi +++ b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi @@ -15,4 +15,5 @@ /include/ "dsi-panel-otm8018b-fwvga-video.dtsi" // lijiangshuo add for lead otm8018b for P821B10 20131226 /include/ "dsi-panel-nt35512-wvga-video.dtsi" /** ZTE_MODIFY zhoufan add for nt35512 ZGD LCD 2014-2-10 */ /include/ "dsi-panel-hx8379c_apex_wvga_video.dtsi" /** ZTE_MODIFY wangzhe add for hx8379c ZGD LCD 2014-6-27 */ -/include/ "dsi-panel-ili9806e_apex_wvga_video.dtsi" /** ZTE_MODIFY wangzhe add for ili9806e ZGD LCD 2014-8-29 */ \ No newline at end of file +/include/ "dsi-panel-ili9806e_apex_wvga_video.dtsi" /** ZTE_MODIFY wangzhe add for ili9806e ZGD LCD 2014-8-29 */ +/include/ "dsi-panel-ili9488-hvga-video.dtsi" \ No newline at end of file From 88ef9122ba1707e9d15571a6053a449b4f43aee3 Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Thu, 26 Nov 2015 13:14:36 +1030 Subject: [PATCH 5/6] drivers: input: touchscreen: Import MSG DSX touchscreen. --- arch/arm/boot/dts/msm8610-qrd.dtsi | 10 + drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/msg_21xx_selfcap.c | 3164 ++++++++++++++++++ 4 files changed, 3187 insertions(+) create mode 100644 drivers/input/touchscreen/msg_21xx_selfcap.c diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi index 19106611182e..0a853bf2dcab 100644 --- a/arch/arm/boot/dts/msm8610-qrd.dtsi +++ b/arch/arm/boot/dts/msm8610-qrd.dtsi @@ -56,6 +56,16 @@ focaltech,fw-delay-readid-ms = <10>; focaltech,fw-delay-era-flsh-ms = <2000>; }; + msg21xx_ts@26{ + compatible = "mstar,ms-msg21xx"; + reg = <0x26>; + interrupt-parent = <&msmgpio>; + interrupts = <1 0x2>; + vdd-supply = <&pm8110_l19>; + vcc_i2c-supply = <&pm8110_l14>; + reset-gpio-pin = <&msmgpio 0 0x00>; + irq-gpio-pin = <&msmgpio 1 0x00>; + }; goodix@5d { compatible = "goodix,Goodix-TS"; reg = <0x5d>; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 8083252b5bcf..c70c3262d172 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -969,6 +969,18 @@ config TOUCHSCREEN_GEN_VKEYS To compile this driver as a module, choose M here: the module will be called gen_vkeys. +config TOUCHSCREEN_SYNAPTICS_I2C_MSG + tristate "MSG DSX I2C touchscreen" + depends on I2C + help + Say Y here if you have a MSG DSX I2C touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called msg_21xx_selfcap. + config TOUCHSCREEN_SYNAPTICS_I2C_RMI4 tristate "Synaptics DSX I2C touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index d8d2a346b17d..a47c1d89d9c2 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_zte/ else obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ endif +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_MSG) += msg_21xx_selfcap.o \ No newline at end of file diff --git a/drivers/input/touchscreen/msg_21xx_selfcap.c b/drivers/input/touchscreen/msg_21xx_selfcap.c new file mode 100644 index 000000000000..65a59b87b311 --- /dev/null +++ b/drivers/input/touchscreen/msg_21xx_selfcap.c @@ -0,0 +1,3164 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#include +#define TY_PMU_CTL 1 +#if defined TY_PMU_CTL +#include +#endif +#define MSG_2133_AND_2133A +static unsigned char chip_id; +//------------------------------------------------------------------- +//------------------------------------------------------------------- +#define TYQ_TP_ANDROID4_0_SUPPORT + +#if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) +extern unsigned char ft_probe_flag; +#endif +//#define TYN_VIRTAUL_KEY_FRAMEWORK //add by gaohw +#define u8 unsigned char +#define u32 unsigned int +#define s32 signed int + +#define REPORT_PACKET_LENGTH (8) +#define TY_TP_INT 1 +#define TY_TP_RST 0 + +#define MSG21XX_INT_GPIO (TY_TP_INT) //gaohw +#define MSG21XX_RESET_GPIO (TY_TP_RST) //gaohw + +#define MS_TS_MSG21XX_X_MAX (320) +#define MS_TS_MSG21XX_Y_MAX (480) + +/*#define TOUCH_KEY_HOME (102) +#define TOUCH_KEY_MENU (139) +#define TOUCH_KEY_BACK (158) +*/ + + + +//ADD +#define TYN_TOUCH_FMUPGRADE 0x6501 +#define TYN_TOUCH_FWVER (TYN_TOUCH_FMUPGRADE +1 ) +#define TYN_TOUCH_VENDOR (TYN_TOUCH_FMUPGRADE +2 ) +#define TYN_TOUCH_CHIPID (TYN_TOUCH_FMUPGRADE +3 ) +#define NV_TOUCH_FT +#define TYN_TOUCH_FOCALTECH 1 + +struct ty_touch_fmupgrade_S +{ + unsigned int touchType; + unsigned long ulCRC; + unsigned long ulReserved; + unsigned long bufLength; + void* bufAddr; +}; +static struct touch_ctrl_dev +{ + dev_t devno; + struct cdev cdev; + struct class *class; +}ty_touch_ctrl; + + + + +static int msg21xx_irq = 0; +static struct i2c_client *msg21xx_i2c_client; +static struct work_struct msg21xx_wq; + + +#if defined(CONFIG_FB) +struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static struct early_suspend early_suspend; +#endif +static struct input_dev *input = NULL; +/*********start::add by gaohw***********/ +struct mstar_tp_irq_status { + volatile unsigned long irqen; +}; +static struct mstar_tp_irq_status mstar_tp_status; +/**********end:: add by gaohw********/ +struct msg21xx_ts_data +{ + uint16_t addr; + struct i2c_client *client; + struct input_dev *input_dev; + int use_irq; + struct work_struct work; + int (*power)(int on); + int (*get_int_status)(void); + void (*reset_ic)(void); +}; + + +#define MAX_TOUCH_FINGER 2 +typedef struct +{ + u16 X; + u16 Y; +} TouchPoint_t; + +typedef struct +{ + u8 nTouchKeyMode; + u8 nTouchKeyCode; + u8 nFingerNum; + TouchPoint_t Point[MAX_TOUCH_FINGER]; +} TouchScreenInfo_t; + +//--------------------------------------------------------------------------- +#define __FIRMWARE_UPDATE__ +#ifdef __FIRMWARE_UPDATE__ +//#define AUTO_UPDATE // no need to update +#ifdef AUTO_UPDATE +static u8 bFwUpdating = 0; + +static struct work_struct msg21xx_wq_gao; +#endif + +#define FW_ADDR_MSG21XX (0xC4>>1) +#define FW_ADDR_MSG21XX_TP (0x4C>>1) +#define FW_UPDATE_ADDR_MSG21XX (0x92>>1) +#define TP_DEBUG printk +static char *fw_version; + +static unsigned short major_version; +static unsigned short minor_version; +#ifdef AUTO_UPDATE +static unsigned short fm_major_version; +static unsigned short fm_minor_version; +#endif +static u8 temp[94][1024]; +static int FwDataCnt; +struct class *firmware_class; +struct device *firmware_cmd_dev; + +static int touch_ctrl_init(void *touch); + +#if defined TY_PMU_CTL +struct regulator *vdd; +struct regulator *vcc_i2c; + +#define MSTAR_VTG_MIN_UV 2800000 +#define MSTAR_VTG_MAX_UV 3300000 +#define MSTAR_I2C_VTG_MIN_UV 1800000 +#define MSTAR_I2C_VTG_MAX_UV 1800000 +#define MSTAR_VDD_LOAD_MIN_UA 0 +#define MSTAR_VDD_LOAD_MAX_UA 10000 +#define MSTAR_VIO_LOAD_MIN_UA 0 +#define MSTAR_VIO_LOAD_MAX_UA 10000 + + +/** + * mstar_power_on - Turn device power ON + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int mstar_power_on(void) +{ + + int rc; + printk("mstar_power_on++++++\n"); + + if ( !vdd) + { + printk("vdd is NULL\n"); + return -1; + } + + + rc = regulator_enable( vdd); + if (rc) { + dev_err(&msg21xx_i2c_client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + return rc; + } + rc = regulator_enable( vcc_i2c); + if (rc) { + dev_err(& msg21xx_i2c_client->dev, + "Regulator vcc_i2c enable failed rc=%d\n", rc); + regulator_disable( vdd); + } + return rc; +} +#if 1 +/** + * mstar_power_off - Turn device power OFF + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int mstar_power_off(void) +{ + int rc; + printk("mstar_power_off-------\n"); + + if ( !vdd) + { + printk("vdd is NULL\n"); + + return -1; + } + + rc = regulator_disable( vdd); + if (rc) { + dev_err(& msg21xx_i2c_client->dev, + "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_disable( vcc_i2c); + if (rc) { + dev_err(&msg21xx_i2c_client->dev, + "Regulator vcc_i2c disable failed rc=%d\n", rc); + regulator_enable( vdd); + } + + return rc; +} +#endif + +/** + * mstar_power_init - Initialize device power + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int mstar_power_init(void) +{ + int rc; + + + vdd = regulator_get(&msg21xx_i2c_client->dev, "vdd"); + if (IS_ERR(vdd)) { + rc = PTR_ERR(vdd); + dev_err(&msg21xx_i2c_client->dev, + "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(vdd) > 0) { + rc = regulator_set_voltage(vdd, MSTAR_VTG_MIN_UV, + MSTAR_VTG_MAX_UV); + if (rc) { + dev_err(&msg21xx_i2c_client->dev, + "Regulator set_vtg failed vdd rc=%d\n", rc); + goto reg_vdd_put; + } + } + vcc_i2c = regulator_get(&msg21xx_i2c_client->dev, "vcc_i2c"); + if (IS_ERR(vcc_i2c)) { + rc = PTR_ERR(vcc_i2c); + dev_err(&msg21xx_i2c_client->dev, + "Regulator get failed vcc_i2c rc=%d\n", rc); + goto reg_vdd_set_vtg; + } + + if (regulator_count_voltages(vcc_i2c) > 0) { + rc = regulator_set_voltage(vcc_i2c, MSTAR_I2C_VTG_MIN_UV, + MSTAR_I2C_VTG_MAX_UV); + if (rc) { + dev_err(&msg21xx_i2c_client->dev, + "Regulator set_vtg failed vcc_i2c rc=%d\n", rc); + goto reg_vcc_i2c_put; + } + } + return 0; + +reg_vcc_i2c_put: + regulator_put(vcc_i2c); +reg_vdd_set_vtg: + if (regulator_count_voltages(vdd) > 0) + regulator_set_voltage(vdd, 0, MSTAR_VTG_MAX_UV); + +reg_vdd_put: + regulator_put(vdd); + return rc; +} +#if 1 +/** + * mstar_power_deinit - Deinitialize device power + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int mstar_power_deinit(void) +{ + if (regulator_count_voltages(vdd) > 0) + regulator_set_voltage(vdd, 0, MSTAR_VTG_MAX_UV); + + regulator_put(vdd); + + if (regulator_count_voltages(vcc_i2c) > 0) + regulator_set_voltage(vcc_i2c, 0, MSTAR_I2C_VTG_MAX_UV); + + regulator_put(vcc_i2c); + return 0; +} +#endif +#endif +static void HalTscrCReadI2CSeq(u8 addr, u8* read_data, u16 size) +{ + //according to your platform. + int rc; + + struct i2c_msg msgs[] = + { + { + .addr = addr, + .flags = I2C_M_RD, + .len = size, + .buf = read_data, + }, + }; + + rc = i2c_transfer(msg21xx_i2c_client->adapter, msgs, 1); + if( rc < 0 ) + { + printk("HalTscrCReadI2CSeq error %d\n", rc); + } +} + +static void HalTscrCDevWriteI2CSeq(u8 addr, u8* data, u16 size) +{ + //according to your platform. + int rc; + + struct i2c_msg msgs[] = + { + { + .addr = addr, + .flags = 0, + .len = size, + .buf = data, + }, + }; + rc = i2c_transfer(msg21xx_i2c_client->adapter, msgs, 1); + if( rc < 0 ) + { + printk("HalTscrCDevWriteI2CSeq error %d,addr = %d\n", rc,addr); + } +} + +static void dbbusDWIICEnterSerialDebugMode(void) +{ + u8 data[5]; + + // Enter the Serial Debug Mode + data[0] = 0x53; + data[1] = 0x45; + data[2] = 0x52; + data[3] = 0x44; + data[4] = 0x42; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 5); +} + +static void dbbusDWIICStopMCU(void) +{ + u8 data[1]; + + // Stop the MCU + data[0] = 0x37; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); +} + +static void dbbusDWIICIICUseBus(void) +{ + u8 data[1]; + + // IIC Use Bus + data[0] = 0x35; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); +} + +static void dbbusDWIICIICReshape(void) +{ + u8 data[1]; + + // IIC Re-shape + data[0] = 0x71; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); +} + +static void dbbusDWIICIICNotUseBus(void) +{ + u8 data[1]; + + // IIC Not Use Bus + data[0] = 0x34; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); +} + +static void dbbusDWIICNotStopMCU(void) +{ + u8 data[1]; + + // Not Stop the MCU + data[0] = 0x36; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); +} + +static void dbbusDWIICExitSerialDebugMode(void) +{ + u8 data[1]; + + // Exit the Serial Debug Mode + data[0] = 0x45; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, data, 1); + + // Delay some interval to guard the next transaction + //udelay ( 200 ); // delay about 0.2ms +} + +static void drvISP_EntryIspMode(void) +{ + u8 bWriteData[5] = + { + 0x4D, 0x53, 0x54, 0x41, 0x52 + }; + + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 5); +} + +static u8 drvISP_Read(u8 n, u8* pDataToRead) //First it needs send 0x11 to notify we want to get flash data back. +{ + u8 Read_cmd = 0x11; + unsigned char dbbus_rx_data[2] = {0}; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &Read_cmd, 1); + udelay(100); // delay about 100us***** + if (n == 1) + { + HalTscrCReadI2CSeq(FW_UPDATE_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + *pDataToRead = dbbus_rx_data[0]; + } + else + { + HalTscrCReadI2CSeq(FW_UPDATE_ADDR_MSG21XX, pDataToRead, n); + } + + return 0; +} + +static void drvISP_WriteEnable(void) +{ + u8 bWriteData[2] = + { + 0x10, 0x06 + }; + u8 bWriteData1 = 0x12; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 2); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); +} + + +static void drvISP_ExitIspMode(void) +{ + u8 bWriteData = 0x24; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData, 1); +} + +static u8 drvISP_ReadStatus(void) +{ + u8 bReadData = 0; + u8 bWriteData[2] = + { + 0x10, 0x05 + }; + u8 bWriteData1 = 0x12; + + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 2); + udelay(100); // delay about 100us***** + drvISP_Read(1, &bReadData); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + return bReadData; +} + + +static void drvISP_ChipErase(void) +{ + u8 bWriteData[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 bWriteData1 = 0x12; + u32 timeOutCount=0; + drvISP_WriteEnable(); + + //Enable write status register + bWriteData[0] = 0x10; + bWriteData[1] = 0x50; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 2); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + + //Write Status + bWriteData[0] = 0x10; + bWriteData[1] = 0x01; + bWriteData[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 3); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + + //Write disable + bWriteData[0] = 0x10; + bWriteData[1] = 0x04; + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 2); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + udelay(100); // delay about 100us***** + timeOutCount=0; + while ( ( drvISP_ReadStatus() & 0x01 ) == 0x01 ) + { + timeOutCount++; + if ( timeOutCount >= 100000 ) break; /* around 1 sec timeout */ + } + drvISP_WriteEnable(); + + bWriteData[0] = 0x10; + bWriteData[1] = 0xC7; + + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 2); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + udelay(100); // delay about 100us***** + timeOutCount=0; + while ( ( drvISP_ReadStatus() & 0x01 ) == 0x01 ) + { + timeOutCount++; + if ( timeOutCount >= 500000 ) break; /* around 5 sec timeout */ + } +} + +static void drvISP_Program(u16 k, u8* pDataToWrite) +{ + u16 i = 0; + u16 j = 0; + //u16 n = 0; + u8 TX_data[133]; + u8 bWriteData1 = 0x12; + u32 addr = k * 1024; + u32 timeOutCount=0; + for (j = 0; j < 8; j++) //128*8 cycle + { + TX_data[0] = 0x10; + TX_data[1] = 0x02;// Page Program CMD + TX_data[2] = (addr + 128 * j) >> 16; + TX_data[3] = (addr + 128 * j) >> 8; + TX_data[4] = (addr + 128 * j); + for (i = 0; i < 128; i++) + { + TX_data[5 + i] = pDataToWrite[j * 128 + i]; + } + udelay(100); // delay about 100us***** + + timeOutCount=0; + while ( ( drvISP_ReadStatus() & 0x01 ) == 0x01 ) + { + timeOutCount++; + if ( timeOutCount >= 100000 ) break; /* around 1 sec timeout */ + } + + + + drvISP_WriteEnable(); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, TX_data, 133); //write 133 byte per cycle + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); + } +} + + +static void drvISP_Verify(u16 k, u8* pDataToVerify) +{ + u16 i = 0, j = 0; + u8 bWriteData[5] = + { + 0x10, 0x03, 0, 0, 0 + }; + u8 RX_data[256]; + u8 bWriteData1 = 0x12; + u32 addr = k * 1024; + u8 index=0; + u32 timeOutCount; + for (j = 0; j < 8; j++) //128*8 cycle + { + bWriteData[2] = (u8)((addr + j * 128) >> 16); + bWriteData[3] = (u8)((addr + j * 128) >> 8); + bWriteData[4] = (u8)(addr + j * 128); + udelay(100); // delay about 100us***** + + + timeOutCount=0; + while ( ( drvISP_ReadStatus() & 0x01 ) == 0x01 ) + { + timeOutCount++; + if ( timeOutCount >= 100000 ) break; /* around 1 sec timeout */ + } + + + + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 5); //write read flash addr + udelay(100); // delay about 100us***** + drvISP_Read(128, RX_data); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); //cmd end + for (i = 0; i < 128; i++) //log out if verify error + { + if((RX_data[i]!=0)&&index<10) + { + //TP_DEBUG("j=%d,RX_data[%d]=0x%x\n",j,i,RX_data[i]); + index++; + } + if (RX_data[i] != pDataToVerify[128 * j + i]) + { + TP_DEBUG("k=%d,j=%d,i=%d===============Update Firmware Error================",k,j,i); + } + } + } +} + +static ssize_t firmware_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", fw_version); +} + +static void _HalTscrHWReset(void) +{ + // gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + gpio_direction_output(MSG21XX_RESET_GPIO, 1); + gpio_set_value(MSG21XX_RESET_GPIO, 1); + gpio_set_value(MSG21XX_RESET_GPIO, 0); + mdelay(10); /* Note that the RST must be in LOW 10ms at least */ + gpio_set_value(MSG21XX_RESET_GPIO, 1); + /* Enable the interrupt service thread/routine for INT after 50ms */ + mdelay(300); +// gpio_free(MSG21XX_RESET_GPIO); +} +static u8 get_chip_id(void) +{ + u8 dbbus_tx_data[4]; + unsigned char dbbus_rx_data[2] = {0}; + // disable_irq(msg21xx_irq); + + _HalTscrHWReset(); + // Erase TP Flash first + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + mdelay ( 300 ); + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + // Stop MCU + #ifdef doubleeee + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0xE4; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + #else + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + #endif + ///////////////////////// + // Difference between C2 and C3 + ///////////////////////// + // c2:2133 c32:2133a(2) c33:2138 + //check id + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0xCC; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + _HalTscrHWReset(); +// enable_irq(msg21xx_irq); + return dbbus_rx_data[0] ; + +} +#ifdef MSG_2133_AND_2133A +u32 crc_tab[256]; +static u8 g_dwiic_info_data[1024]; // Buffer for info data + +static u32 Reflect ( u32 ref, char ch ) //unsigned int Reflect(unsigned int ref, char ch) +{ + u32 value = 0; + u32 i = 0; + + for ( i = 1; i < ( ch + 1 ); i++ ) + { + if ( ref & 1 ) + { + value |= 1 << ( ch - i ); + } + ref >>= 1; + } + return value; +} + +u32 Get_CRC ( u32 text, u32 prevCRC, u32 *crc32_table ) +{ + u32 ulCRC = prevCRC; + ulCRC = ( ulCRC >> 8 ) ^ crc32_table[ ( ulCRC & 0xFF ) ^ text]; + return ulCRC ; +} +static void Init_CRC32_Table ( u32 *crc32_table ) +{ + u32 magicnumber = 0x04c11db7; + u32 i = 0, j; + + for ( i = 0; i <= 0xFF; i++ ) + { + crc32_table[i] = Reflect ( i, 8 ) << 24; + for ( j = 0; j < 8; j++ ) + { + crc32_table[i] = ( crc32_table[i] << 1 ) ^ ( crc32_table[i] & ( 0x80000000L ) ? magicnumber : 0 ); + } + crc32_table[i] = Reflect ( crc32_table[i], 32 ); + } +} + +typedef enum +{ + EMEM_ALL = 0, + EMEM_MAIN, + EMEM_INFO, +} EMEM_TYPE_t; + +static void drvDB_WriteReg8Bit ( u8 bank, u8 addr, u8 data ) +{ + u8 tx_data[4] = {0x10, bank, addr, data}; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, tx_data, 4 ); +} +static void drvDB_WriteReg ( u8 bank, u8 addr, u16 data ) +{ + u8 tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8}; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, tx_data, 5 ); +} + +static unsigned short drvDB_ReadReg ( u8 bank, u8 addr ) +{ + u8 tx_data[3] = {0x10, bank, addr}; + u8 rx_data[2] = {0}; + + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, tx_data, 3 ); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &rx_data[0], 2 ); + return ( rx_data[1] << 8 | rx_data[0] ); +} + +/* +static int drvTP_erase_emem_c32 ( void ) +{ + ///////////////////////// + //Erase all + ///////////////////////// + + //enter gpio mode + drvDB_WriteReg ( 0x16, 0x1E, 0xBEAF ); + + // before gpio mode, set the control pin as the orginal status + drvDB_WriteReg ( 0x16, 0x08, 0x0000 ); + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x10 ); + mdelay ( 10 ); //MCR_CLBK_DEBUG_DELAY ( 10, MCU_LOOP_DELAY_COUNT_MS ); + + // ptrim = 1, h'04[2] + drvDB_WriteReg8Bit ( 0x16, 0x08, 0x04 ); + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x10 ); + mdelay ( 10 ); //MCR_CLBK_DEBUG_DELAY ( 10, MCU_LOOP_DELAY_COUNT_MS ); + + // ptm = 6, h'04[12:14] = b'110 + drvDB_WriteReg8Bit ( 0x16, 0x09, 0x60 ); + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x10 ); + + // pmasi = 1, h'04[6] + drvDB_WriteReg8Bit ( 0x16, 0x08, 0x44 ); + // pce = 1, h'04[11] + drvDB_WriteReg8Bit ( 0x16, 0x09, 0x68 ); + // perase = 1, h'04[7] + drvDB_WriteReg8Bit ( 0x16, 0x08, 0xC4 ); + // pnvstr = 1, h'04[5] + drvDB_WriteReg8Bit ( 0x16, 0x08, 0xE4 ); + // pwe = 1, h'04[9] + drvDB_WriteReg8Bit ( 0x16, 0x09, 0x6A ); + // trigger gpio load + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x10 ); + + return ( 1 ); +} +*/ +static int drvTP_erase_emem_c33 ( EMEM_TYPE_t emem_type ) +{ + // stop mcu + drvDB_WriteReg ( 0x0F, 0xE6, 0x0001 ); + + //disable watch dog + drvDB_WriteReg8Bit ( 0x3C, 0x60, 0x55 ); + drvDB_WriteReg8Bit ( 0x3C, 0x61, 0xAA ); + + // set PROGRAM password + drvDB_WriteReg8Bit ( 0x16, 0x1A, 0xBA ); + drvDB_WriteReg8Bit ( 0x16, 0x1B, 0xAB ); + + //proto.MstarWriteReg(F1.loopDevice, 0x1618, 0x80); + drvDB_WriteReg8Bit ( 0x16, 0x18, 0x80 ); + + if ( emem_type == EMEM_ALL ) + { + drvDB_WriteReg8Bit ( 0x16, 0x08, 0x10 ); //mark + } + + drvDB_WriteReg8Bit ( 0x16, 0x18, 0x40 ); + mdelay ( 10 ); + + drvDB_WriteReg8Bit ( 0x16, 0x18, 0x80 ); + + // erase trigger + if ( emem_type == EMEM_MAIN ) + { + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x04 ); //erase main + } + else + { + drvDB_WriteReg8Bit ( 0x16, 0x0E, 0x08 ); //erase all block + } + + return ( 1 ); +} +/* +static int drvTP_read_emem_dbbus_c33 ( EMEM_TYPE_t emem_type, u16 addr, size_t size, u8 *p, size_t set_pce_high ) +{ + u32 i; + + // Set the starting address ( must before enabling burst mode and enter riu mode ) + drvDB_WriteReg ( 0x16, 0x00, addr ); + + // Enable the burst mode ( must before enter riu mode ) + drvDB_WriteReg ( 0x16, 0x0C, drvDB_ReadReg ( 0x16, 0x0C ) | 0x0001 ); + + // Set the RIU password + drvDB_WriteReg ( 0x16, 0x1A, 0xABBA ); + + // Enable the information block if pifren is HIGH + if ( emem_type == EMEM_INFO ) + { + // Clear the PCE + drvDB_WriteReg ( 0x16, 0x18, drvDB_ReadReg ( 0x16, 0x18 ) | 0x0080 ); + mdelay ( 10 ); + + // Set the PIFREN to be HIGH + drvDB_WriteReg ( 0x16, 0x08, 0x0010 ); + } + + // Set the PCE to be HIGH + drvDB_WriteReg ( 0x16, 0x18, drvDB_ReadReg ( 0x16, 0x18 ) | 0x0040 ); + mdelay ( 10 ); + + // Wait pce becomes 1 ( read data ready ) + while ( ( drvDB_ReadReg ( 0x16, 0x10 ) & 0x0004 ) != 0x0004 ); + + for ( i = 0; i < size; i += 4 ) + { + // Fire the FASTREAD command + drvDB_WriteReg ( 0x16, 0x0E, drvDB_ReadReg ( 0x16, 0x0E ) | 0x0001 ); + + // Wait the operation is done + while ( ( drvDB_ReadReg ( 0x16, 0x10 ) & 0x0001 ) != 0x0001 ); + + p[i + 0] = drvDB_ReadReg ( 0x16, 0x04 ) & 0xFF; + p[i + 1] = ( drvDB_ReadReg ( 0x16, 0x04 ) >> 8 ) & 0xFF; + p[i + 2] = drvDB_ReadReg ( 0x16, 0x06 ) & 0xFF; + p[i + 3] = ( drvDB_ReadReg ( 0x16, 0x06 ) >> 8 ) & 0xFF; + } + + // Disable the burst mode + drvDB_WriteReg ( 0x16, 0x0C, drvDB_ReadReg ( 0x16, 0x0C ) & ( ~0x0001 ) ); + + // Clear the starting address + drvDB_WriteReg ( 0x16, 0x00, 0x0000 ); + + //Always return to main block + if ( emem_type == EMEM_INFO ) + { + // Clear the PCE before change block + drvDB_WriteReg ( 0x16, 0x18, drvDB_ReadReg ( 0x16, 0x18 ) | 0x0080 ); + mdelay ( 10 ); + // Set the PIFREN to be LOW + drvDB_WriteReg ( 0x16, 0x08, drvDB_ReadReg ( 0x16, 0x08 ) & ( ~0x0010 ) ); + + drvDB_WriteReg ( 0x16, 0x18, drvDB_ReadReg ( 0x16, 0x18 ) | 0x0040 ); + while ( ( drvDB_ReadReg ( 0x16, 0x10 ) & 0x0004 ) != 0x0004 ); + } + + // Clear the RIU password + drvDB_WriteReg ( 0x16, 0x1A, 0x0000 ); + + if ( set_pce_high ) + { + // Set the PCE to be HIGH before jumping back to e-flash codes + drvDB_WriteReg ( 0x16, 0x18, drvDB_ReadReg ( 0x16, 0x18 ) | 0x0040 ); + while ( ( drvDB_ReadReg ( 0x16, 0x10 ) & 0x0004 ) != 0x0004 ); + } + + return ( 1 ); +} + +*/ +#if 1 +static int drvTP_read_info_dwiic_c33 ( void ) +{ + //u8 i; + u8 dwiic_tx_data[5]; + // u8 dwiic_rx_data[4]; + u16 reg_data=0; + mdelay ( 300 ); + + // Stop Watchdog + drvDB_WriteReg8Bit ( 0x3C, 0x60, 0x55 ); + drvDB_WriteReg8Bit ( 0x3C, 0x61, 0xAA ); + + drvDB_WriteReg ( 0x3C, 0xE4, 0xA4AB ); + + drvDB_WriteReg ( 0x1E, 0x04, 0x7d60 ); + + // TP SW reset + drvDB_WriteReg ( 0x1E, 0x04, 0x829F ); + mdelay ( 1 ); + dwiic_tx_data[0] = 0x10; + dwiic_tx_data[1] = 0x0F; + dwiic_tx_data[2] = 0xE6; + dwiic_tx_data[3] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dwiic_tx_data, 4 ); + mdelay ( 100 ); + + do{ + printk("*********gaohw::reg_data != 0x5B58********\n"); + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + } + while ( reg_data != 0x5B58 ); + printk("( reg_data != 0x5B58 );\n"); + + #if 0 + dwiic_tx_data[0] = 0x72; + dwiic_tx_data[1] = 0x80; + dwiic_tx_data[2] = 0x00; + dwiic_tx_data[3] = 0x04; + dwiic_tx_data[4] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX_TP , dwiic_tx_data, 5 ); + + mdelay ( 50 ); + + // recive info data + #if 0 + for (i=0;i<256;i++) + { + mdelay(20); + printk("i=%d\n",i); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX_TP, &g_dwiic_info_data[i*4], 4 ); + } + #endif + + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX_TP, &g_dwiic_info_data[0], 8 ); + + #else + dwiic_tx_data[0] = 0x72; + + // dwiic_tx_data[3] = 0x04; + // dwiic_tx_data[4] = 0x00; + dwiic_tx_data[3] = 0x00; + dwiic_tx_data[4] = 0x08; + + for(reg_data=0;reg_data<128;reg_data++) + { + dwiic_tx_data[1] = (((reg_data*8)&0xff00)>>8)+0x80; // address High + dwiic_tx_data[2] = (reg_data*8)&0x00ff; // address low + + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX_TP , dwiic_tx_data, 5 ); + + mdelay (50 ); + + // recive info data + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX_TP, &g_dwiic_info_data[reg_data*8], 8); + } + #endif + return ( 1 ); +} +#endif +static ssize_t firmware_update_c33 ( struct device *dev, struct device_attribute *attr, + const char *buf, size_t size, EMEM_TYPE_t emem_type ) +{ + // u8 dbbus_tx_data[4]; + //u8 dbbus_rx_data[2] = {0}; + u8 life_counter[2]; + u32 i, j; + u32 crc_main, crc_main_tp; + u32 crc_info, crc_info_tp; + + int update_pass = 1; + u16 reg_data = 0; + + crc_main = 0xffffffff; + crc_info = 0xffffffff; + + drvTP_read_info_dwiic_c33(); + printk("drvTP_read_info_dwiic_c33\n"); + if ( g_dwiic_info_data[0] == 'M' && g_dwiic_info_data[1] == 'S' && g_dwiic_info_data[2] == 'T' && g_dwiic_info_data[3] == 'A' && g_dwiic_info_data[4] == 'R' && g_dwiic_info_data[5] == 'T' && g_dwiic_info_data[6] == 'P' && g_dwiic_info_data[7] == 'C' ) + { + // updata FW Version + //drvTP_info_updata_C33 ( 8, &temp[32][8], 5 ); + + g_dwiic_info_data[8]=temp[32][8]; + g_dwiic_info_data[9]=temp[32][9]; + g_dwiic_info_data[10]=temp[32][10]; + g_dwiic_info_data[11]=temp[32][11]; + // updata life counter + life_counter[1] = (( ( (g_dwiic_info_data[13] << 8 ) | g_dwiic_info_data[12]) + 1 ) >> 8 ) & 0xFF; + life_counter[0] = ( ( (g_dwiic_info_data[13] << 8 ) | g_dwiic_info_data[12]) + 1 ) & 0xFF; + g_dwiic_info_data[12]=life_counter[0]; + g_dwiic_info_data[13]=life_counter[1]; + //drvTP_info_updata_C33 ( 10, &life_counter[0], 3 ); + drvDB_WriteReg ( 0x3C, 0xE4, 0x78C5 ); + drvDB_WriteReg ( 0x1E, 0x04, 0x7d60 ); + // TP SW reset + drvDB_WriteReg ( 0x1E, 0x04, 0x829F ); + + mdelay ( 1500 ); + pr_debug("TP SW reset still busy ******************\n"); + //polling 0x3CE4 is 0x2F43 + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + + } + while ( reg_data != 0x2F43 ); + + printk("2F43 still busy ******************\n"); + // transmit lk info data + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX_TP , &g_dwiic_info_data[0], 1024 ); + printk("transmit lk info data\n"); + mdelay(100); + //polling 0x3CE4 is 0xD0BC + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + } + while ( reg_data != 0xD0BC ); + printk("0xD0BC still busy ******************\n"); + + } + + //erase main + drvTP_erase_emem_c33 ( EMEM_MAIN ); + printk("erase main\n"); + mdelay ( 1000 ); + + //ResetSlave(); + _HalTscrHWReset(); + + //drvDB_EnterDBBUS(); + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + mdelay ( 300 ); + + ///////////////////////// + // Program + ///////////////////////// + + //polling 0x3CE4 is 0x1C70 + if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) + { + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + } + while ( reg_data != 0x1C70 ); + } + printk("Program\n"); + switch ( emem_type ) + { + case EMEM_ALL: + drvDB_WriteReg ( 0x3C, 0xE4, 0xE38F ); // for all-blocks + break; + case EMEM_MAIN: + drvDB_WriteReg ( 0x3C, 0xE4, 0x7731 ); // for main block + break; + case EMEM_INFO: + drvDB_WriteReg ( 0x3C, 0xE4, 0x7731 ); // for info block + + drvDB_WriteReg8Bit ( 0x0F, 0xE6, 0x01 ); + + drvDB_WriteReg8Bit ( 0x3C, 0xE4, 0xC5 ); // + drvDB_WriteReg8Bit ( 0x3C, 0xE5, 0x78 ); // + + drvDB_WriteReg8Bit ( 0x1E, 0x04, 0x9F ); + drvDB_WriteReg8Bit ( 0x1E, 0x05, 0x82 ); + + drvDB_WriteReg8Bit ( 0x0F, 0xE6, 0x00 ); + mdelay ( 100 ); + break; + } + + // polling 0x3CE4 is 0x2F43 + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + } + while ( reg_data != 0x2F43 ); + printk("polling 0x3CE4 is 0x2F43\n"); + // calculate CRC 32 + Init_CRC32_Table ( &crc_tab[0] ); + + for ( i = 0; i < 33; i++ ) // total 33 KB : 2 byte per R/W + { + if ( emem_type == EMEM_INFO ) + i = 32; + + if ( i < 32 ) //emem_main + { + if ( i == 31 ) + { + temp[i][1014] = 0x5A; //Fmr_Loader[1014]=0x5A; + temp[i][1015] = 0xA5; //Fmr_Loader[1015]=0xA5; + + for ( j = 0; j < 1016; j++ ) + { + //crc_main=Get_CRC(Fmr_Loader[j],crc_main,&crc_tab[0]); + crc_main = Get_CRC ( temp[i][j], crc_main, &crc_tab[0] ); + } + } + else + { + for ( j = 0; j < 1024; j++ ) + { + //crc_main=Get_CRC(Fmr_Loader[j],crc_main,&crc_tab[0]); + crc_main = Get_CRC ( temp[i][j], crc_main, &crc_tab[0] ); + } + } + } + else //emem_info + { + for ( j = 0; j < 1024; j++ ) + { + //crc_info=Get_CRC(Fmr_Loader[j],crc_info,&crc_tab[0]); + crc_info = Get_CRC ( g_dwiic_info_data[j], crc_info, &crc_tab[0] ); + } + if ( emem_type == EMEM_MAIN ) break; + } + + //drvDWIIC_MasterTransmit( DWIIC_MODE_DWIIC_ID, 1024, Fmr_Loader ); + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX_TP, temp[i], 1024 ); + + // polling 0x3CE4 is 0xD0BC + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + } + while ( reg_data != 0xD0BC ); + + drvDB_WriteReg ( 0x3C, 0xE4, 0x2F43 ); + } + + if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) + { + // write file done and check crc + drvDB_WriteReg ( 0x3C, 0xE4, 0x1380 ); + } + mdelay ( 10 ); //MCR_CLBK_DEBUG_DELAY ( 10, MCU_LOOP_DELAY_COUNT_MS ); + + if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) + { + // polling 0x3CE4 is 0x9432 + do + { + reg_data = drvDB_ReadReg ( 0x3C, 0xE4 ); + }while ( reg_data != 0x9432 ); + } + + crc_main = crc_main ^ 0xffffffff; + crc_info = crc_info ^ 0xffffffff; + + if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) + { + // CRC Main from TP + crc_main_tp = drvDB_ReadReg ( 0x3C, 0x80 ); + crc_main_tp = ( crc_main_tp << 16 ) | drvDB_ReadReg ( 0x3C, 0x82 ); + + // CRC Info from TP + crc_info_tp = drvDB_ReadReg ( 0x3C, 0xA0 ); + crc_info_tp = ( crc_info_tp << 16 ) | drvDB_ReadReg ( 0x3C, 0xA2 ); + } + TP_DEBUG ( "crc_main=0x%x, crc_info=0x%x, crc_main_tp=0x%x, crc_info_tp=0x%x\n", + crc_main, crc_info, crc_main_tp, crc_info_tp ); + + //drvDB_ExitDBBUS(); + + update_pass = 1; + if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) + { + if ( crc_main_tp != crc_main ) + update_pass = 0; + + if ( crc_info_tp != crc_info ) + update_pass = 0; + } + + if ( !update_pass ) + { + printk ( "update FAILED\n" ); + _HalTscrHWReset(); + FwDataCnt = 0; + // enable_irq(msg21xx_irq); + return ( 0 ); + } + + printk ( "update OK\n" ); + _HalTscrHWReset(); + FwDataCnt = 0; + //enable_irq(msg21xx_irq); + return size; +} + +static ssize_t firmware_update_c2 ( struct device *dev, + struct device_attribute *attr, const char *buf, size_t size ) +{ + u8 i; + u8 dbbus_tx_data[4]; + unsigned char dbbus_rx_data[2] = {0}; + + // set FRO to 50M + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x11; + dbbus_tx_data[2] = 0xE2; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + dbbus_rx_data[0] = 0; + dbbus_rx_data[1] = 0; + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + TP_DEBUG ( "dbbus_rx_data[0]=0x%x", dbbus_rx_data[0] ); + dbbus_tx_data[3] = dbbus_rx_data[0] & 0xF7; //Clear Bit 3 + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // set MCU clock,SPI clock =FRO + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x22; + dbbus_tx_data[3] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x23; + dbbus_tx_data[3] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // Enable slave's ISP ECO mode + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x08; + dbbus_tx_data[2] = 0x0c; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // Enable SPI Pad + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x02; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + TP_DEBUG ( "dbbus_rx_data[0]=0x%x", dbbus_rx_data[0] ); + dbbus_tx_data[3] = ( dbbus_rx_data[0] | 0x20 ); //Set Bit 5 + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // WP overwrite + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x0E; + dbbus_tx_data[3] = 0x02; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // set pin high + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x10; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + dbbusDWIICIICNotUseBus(); + dbbusDWIICNotStopMCU(); + dbbusDWIICExitSerialDebugMode(); + + drvISP_EntryIspMode(); + drvISP_ChipErase(); + _HalTscrHWReset(); + mdelay ( 300 ); + + // Program and Verify + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + //Stop MCU + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // set FRO to 50M + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x11; + dbbus_tx_data[2] = 0xE2; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + dbbus_rx_data[0] = 0; + dbbus_rx_data[1] = 0; + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + TP_DEBUG ( "dbbus_rx_data[0]=0x%x", dbbus_rx_data[0] ); + dbbus_tx_data[3] = dbbus_rx_data[0] & 0xF7; //Clear Bit 3 + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // set MCU clock,SPI clock =FRO + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x22; + dbbus_tx_data[3] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x23; + dbbus_tx_data[3] = 0x00; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // Enable slave's ISP ECO mode + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x08; + dbbus_tx_data[2] = 0x0c; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // Enable SPI Pad + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x02; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + TP_DEBUG ( "dbbus_rx_data[0]=0x%x", dbbus_rx_data[0] ); + dbbus_tx_data[3] = ( dbbus_rx_data[0] | 0x20 ); //Set Bit 5 + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // WP overwrite + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x0E; + dbbus_tx_data[3] = 0x02; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + // set pin high + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x10; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + + dbbusDWIICIICNotUseBus(); + dbbusDWIICNotStopMCU(); + dbbusDWIICExitSerialDebugMode(); + + /////////////////////////////////////// + // Start to load firmware + /////////////////////////////////////// + drvISP_EntryIspMode(); + + for ( i = 0; i < 94; i++ ) // total 94 KB : 1 byte per R/W + { + drvISP_Program ( i, temp[i] ); // program to slave's flash + drvISP_Verify ( i, temp[i] ); //verify data + } + TP_DEBUG ( "update OK\n" ); + drvISP_ExitIspMode(); + FwDataCnt = 0; + // enable_irq(msg21xx_irq); + + return size; +} + +static ssize_t firmware_update_store ( struct device *dev, + struct device_attribute *attr, const char *buf, size_t size ) +{ + // u8 i; + u8 dbbus_tx_data[4]; + unsigned char dbbus_rx_data[2] = {0}; + //disable_irq(msg21xx_irq); + + _HalTscrHWReset(); + + // Erase TP Flash first + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + mdelay ( 300 ); + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + // Stop MCU + #ifdef doubleeee + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0xE4; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + #else + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 4 ); + #endif + ///////////////////////// + // Difference between C2 and C3 + ///////////////////////// + // c2:2133 c32:2133a(2) c33:2138 + //check id + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0xCC; + HalTscrCDevWriteI2CSeq ( FW_ADDR_MSG21XX, dbbus_tx_data, 3 ); + HalTscrCReadI2CSeq ( FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2 ); + if ( dbbus_rx_data[0] == 2 ) + { + printk("***chip id =0x%x\n",dbbus_rx_data[0]); + return firmware_update_c33 ( dev, attr, buf, size, EMEM_MAIN ); + + } + else + { + printk("chip id =0x%x\n",dbbus_rx_data[0]); + return firmware_update_c2 ( dev, attr, buf, size ); + + } +} + +#else +static ssize_t firmware_update_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 i; + u8 dbbus_tx_data[4]; + unsigned char dbbus_rx_data[2] = {0}; + + + _HalTscrHWReset(); + //1.Erase TP Flash first + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + mdelay(300); + + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + //Stop MCU + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set FRO to 50M + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x11; + dbbus_tx_data[2] = 0xE2; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + dbbus_rx_data[0] = 0; + dbbus_rx_data[1] = 0; + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = dbbus_rx_data[0] & 0xF7; //Clear Bit 3 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + + //set MCU clock,SPI clock =FRO + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x22; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x23; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + // Enable slave's ISP ECO mode + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x08; + dbbus_tx_data[2] = 0x0c; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + //Enable SPI Pad + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = (dbbus_rx_data[0] | 0x20); //Set Bit 5 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //WP overwrite + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x0E; + dbbus_tx_data[3] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set pin high + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x10; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbusDWIICIICNotUseBus(); + dbbusDWIICNotStopMCU(); + dbbusDWIICExitSerialDebugMode(); + + + + drvISP_EntryIspMode(); + drvISP_ChipErase(); + _HalTscrHWReset(); + mdelay(300); + + //2.Program and Verify + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + + + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + //Stop MCU + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set FRO to 50M + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x11; + dbbus_tx_data[2] = 0xE2; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + dbbus_rx_data[0] = 0; + dbbus_rx_data[1] = 0; + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = dbbus_rx_data[0] & 0xF7; //Clear Bit 3 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + + //set MCU clock,SPI clock =FRO + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x22; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x23; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + // Enable slave's ISP ECO mode + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x08; + dbbus_tx_data[2] = 0x0c; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + //Enable SPI Pad + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = (dbbus_rx_data[0] | 0x20); //Set Bit 5 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //WP overwrite + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x0E; + dbbus_tx_data[3] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set pin high + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x10; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbusDWIICIICNotUseBus(); + dbbusDWIICNotStopMCU(); + dbbusDWIICExitSerialDebugMode(); + + /////////////////////////////////////// + // Start to load firmware + /////////////////////////////////////// + drvISP_EntryIspMode(); + + for (i = 0; i < 94; i++) // total 94 KB : 1 byte per R/W + { + drvISP_Program(i, temp[i]); // program to slave's flash + drvISP_Verify ( i, temp[i] ); //verify data + } + TP_DEBUG("update OK\n"); + drvISP_ExitIspMode(); + FwDataCnt = 0; + return size; +} +#endif +static DEVICE_ATTR(update, 0644, firmware_update_show, firmware_update_store); + + +#ifdef AUTO_UPDATE +static void _msg_auto_updateFirmware(void) +{ + schedule_work(&msg21xx_wq_gao); + +} +#endif + +/*test=================*/ +static ssize_t firmware_clear_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u16 k=0,i = 0, j = 0; + u8 bWriteData[5] = + { + 0x10, 0x03, 0, 0, 0 + }; + u8 RX_data[256]; + u8 bWriteData1 = 0x12; + u32 addr = 0; + u32 timeOutCount=0; + for (k = 0; k < 94; i++) // total 94 KB : 1 byte per R/W + { + addr = k * 1024; + for (j = 0; j < 8; j++) //128*8 cycle + { + bWriteData[2] = (u8)((addr + j * 128) >> 16); + bWriteData[3] = (u8)((addr + j * 128) >> 8); + bWriteData[4] = (u8)(addr + j * 128); + udelay(100); // delay about 100us***** + + timeOutCount=0; + while ( ( drvISP_ReadStatus() & 0x01 ) == 0x01 ) + { + timeOutCount++; + if ( timeOutCount >= 100000 ) break; /* around 1 sec timeout */ + } + + + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, bWriteData, 5); //write read flash addr + udelay(100); // delay about 100us***** + drvISP_Read(128, RX_data); + HalTscrCDevWriteI2CSeq(FW_UPDATE_ADDR_MSG21XX, &bWriteData1, 1); //cmd end + for (i = 0; i < 128; i++) //log out if verify error + { + if (RX_data[i] != 0xFF) + { + TP_DEBUG("k=%d,j=%d,i=%d===============erase not clean================",k,j,i); + } + } + } + } + TP_DEBUG("read finish\n"); + return sprintf(buf, "%s\n", fw_version); +} + +static ssize_t firmware_clear_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + + u8 dbbus_tx_data[4]; + unsigned char dbbus_rx_data[2] = {0}; + + _HalTscrHWReset(); + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + + + + // Disable the Watchdog + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x60; + dbbus_tx_data[3] = 0x55; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x3C; + dbbus_tx_data[2] = 0x61; + dbbus_tx_data[3] = 0xAA; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + //Stop MCU + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x0F; + dbbus_tx_data[2] = 0xE6; + dbbus_tx_data[3] = 0x01; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set FRO to 50M + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x11; + dbbus_tx_data[2] = 0xE2; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + dbbus_rx_data[0] = 0; + dbbus_rx_data[1] = 0; + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = dbbus_rx_data[0] & 0xF7; //Clear Bit 3 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + + //set MCU clock,SPI clock =FRO + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x22; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x23; + dbbus_tx_data[2] = 0x00; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + // Enable slave's ISP ECO mode + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x08; + dbbus_tx_data[2] = 0x0c; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + //Enable SPI Pad + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 3); + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX, &dbbus_rx_data[0], 2); + TP_DEBUG("dbbus_rx_data[0]=0x%x", dbbus_rx_data[0]); + dbbus_tx_data[3] = (dbbus_rx_data[0] | 0x20); //Set Bit 5 + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //WP overwrite + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x0E; + dbbus_tx_data[3] = 0x02; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + + //set pin high + dbbus_tx_data[0] = 0x10; + dbbus_tx_data[1] = 0x1E; + dbbus_tx_data[2] = 0x10; + dbbus_tx_data[3] = 0x08; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX, dbbus_tx_data, 4); + + dbbusDWIICIICNotUseBus(); + dbbusDWIICNotStopMCU(); + dbbusDWIICExitSerialDebugMode(); + + + /////////////////////////////////////// + // Start to load firmware + /////////////////////////////////////// + drvISP_EntryIspMode(); + TP_DEBUG("chip erase+\n"); + drvISP_ChipErase(); + TP_DEBUG("chip erase-\n"); + drvISP_ExitIspMode(); + return size; +} + +static DEVICE_ATTR(clear, 0644, firmware_clear_show, firmware_clear_store); + +/*test=================*/ +/*Add by Tracy.Lin for update touch panel firmware and get fw version*/ + +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + TP_DEBUG("*** firmware_version_show fw_version = %s***\n", fw_version); + printk("***major = %d ***\n", major_version); + printk("***minor = %d ***\n", minor_version); + return sprintf(buf, "%s\n", fw_version); +} + +static ssize_t firmware_version_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned char dbbus_tx_data[3]; + unsigned char dbbus_rx_data[4] ; + //unsigned short major=0, minor=0; + + fw_version = kzalloc(sizeof(char), GFP_KERNEL); + //SM-BUS GET FW VERSION + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = 0x00; + if(chip_id==0x02) + dbbus_tx_data[2] = 0x2a; //0x74 + else + dbbus_tx_data[2] = 0x74; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX_TP, &dbbus_tx_data[0], 3); + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX_TP, &dbbus_rx_data[0], 4); + + major_version = (dbbus_rx_data[1]<<8)+dbbus_rx_data[0]; + minor_version= (dbbus_rx_data[3]<<8)+dbbus_rx_data[2]; + + TP_DEBUG("***major = %d ***\n", major_version); + TP_DEBUG("***minor = %d ***\n", minor_version); + sprintf(fw_version,"%03d%03d", major_version, minor_version); + + /* major = (dbbus_rx_data[1]<<8)+dbbus_rx_data[0]; + minor = (dbbus_rx_data[3]<<8)+dbbus_rx_data[2]; + + TP_DEBUG("***major = %d ***\n", major); + TP_DEBUG("***minor = %d ***\n", minor); + sprintf(fw_version,"%03d%03d", major, minor); + */ + TP_DEBUG("***fw_version = %s ***\n", fw_version); + + + return size; +} +static DEVICE_ATTR(version, 0644, firmware_version_show, firmware_version_store); + +static int fts_GetFWVer(unsigned long * pu32) +{ + unsigned char dbbus_tx_data[3]; + unsigned char dbbus_rx_data[4] ; + // unsigned short major=0, minor=0; + //SM-BUS GET FW VERSION + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = 0x00; + if(chip_id==0x02) + dbbus_tx_data[2] = 0x2a; //0x74 + else + dbbus_tx_data[2] = 0x74; + HalTscrCDevWriteI2CSeq(FW_ADDR_MSG21XX_TP, &dbbus_tx_data[0], 3); + HalTscrCReadI2CSeq(FW_ADDR_MSG21XX_TP, &dbbus_rx_data[0], 4); + + major_version= (dbbus_rx_data[1]<<8)+dbbus_rx_data[0]; + minor_version= (dbbus_rx_data[3]<<8)+dbbus_rx_data[2]; + + *pu32 = (major_version<<16) | minor_version; + printk("major_version = %d,minor_version=%d,\n",major_version,minor_version); + //*pu32 = 0; + return 0; +} + + +static ssize_t firmware_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return FwDataCnt; +} + +static ssize_t firmware_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + + int i; + TP_DEBUG("***FwDataCnt = %d ***\n", FwDataCnt); + for (i = 0; i < 1024; i++) + { + memcpy(temp[FwDataCnt], buf, 1024); + } + FwDataCnt++; + return size; +} +static DEVICE_ATTR(data, 0644, firmware_data_show, firmware_data_store); +#endif + + +/////////////////////////////////////////////////////////////////////// + +/* +sysfs file format: +key tyep:key value:key center x:key center y:key width:key height + +#define TOUCH_Y_MAX 836 +#define SCREEN_Y_MAX 800 + +*/ +#if 0 +static ssize_t ty_touch_virtual_keys_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, 200, + __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":120:900:100:80" + ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":240:900:100:80" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE) ":360:900:100:80" + "\n"); + +} + +static struct kobj_attribute ty_touch_virtual_keys_attr = { + .attr = { + .name = "virtualkeys.ms-msg21xx", + .mode = S_IRUGO, + }, + .show = &ty_touch_virtual_keys_show, +}; + + +//**********************************************************************// +static struct attribute *ty_touch_properties_attrs[] = { + &ty_touch_virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group ty_touch_properties_attr_group = { + .attrs = ty_touch_properties_attrs, +}; + +//**********************************************************************// + +static int fts_creat_virtual_key_sysfs(void) +{ + struct kobject *properties_kobj; + int ret = 0; + + properties_kobj = kobject_create_and_add("board_properties", NULL); + if (properties_kobj) + ret = sysfs_create_group(properties_kobj, + &ty_touch_properties_attr_group); + if (!properties_kobj || ret) + printk("failed to create board_properties\n"); + + return ret; +} +#endif +//////////////////////////////////////////////////////////////////////////// + + + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB) + +static void msg21xx_suspend(void) +{ + +#ifdef AUTO_UPDATE + if(bFwUpdating) + { + printk("TPD canot enter sleep bFwUpdating=%d\n",bFwUpdating); + return; + } +#endif + printk("Enter %s \n",__func__); + if((msg21xx_irq)&&(test_and_clear_bit(0,&mstar_tp_status.irqen))) //gaohw + disable_irq_nosync(msg21xx_irq); + + cancel_work_sync(&msg21xx_wq); + //gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + gpio_direction_output(MSG21XX_RESET_GPIO, 0); //add by gaohw + gpio_set_value(MSG21XX_RESET_GPIO, 0); + //gpio_free(MSG21XX_RESET_GPIO); //add by gaohw + input_mt_sync(input); + input_sync(input); + printk("TP exit %s \n",__func__); +} + +static void msg21xx_resume(void) +{ +#ifdef AUTO_UPDATE + + if(bFwUpdating) + { + printk("TPD canot enter sleep bFwUpdating=%d ---resume\n",bFwUpdating); + return; + } +#endif + printk("Enter %s \n",__func__); + + /*input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, 3000); + input_report_abs(input, ABS_MT_POSITION_Y, 3000); + input_mt_sync(input); + input_sync(input); + */ + #if 1//defined(TYQ_TBW5913B_SUPPORT) || defined(TYQ_TBW5913C_SUPPORT) + //gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + gpio_direction_output(MSG21XX_RESET_GPIO, 1); //add by gaohw + /*TY:niuli insert 2 msleep(5) to add delay time when system resume, + so lcd will not white background when resume on 2012*/ + msleep(5); + gpio_set_value(MSG21XX_RESET_GPIO, 1); + msleep(50); + //gpio_free(MSG21XX_RESET_GPIO); //add by gaohw + #else + gpio_direction_input(MSG21XX_RESET_GPIO); + /*TY:niuli insert 2 msleep(5) to add delay time when system resume, + so lcd will not white background when resume on 2012*/ + msleep(10); + #endif + if((msg21xx_irq)&&(!test_and_set_bit(0,&mstar_tp_status.irqen))) //add by gaohw + enable_irq(msg21xx_irq); +} +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + #if 0 + struct ft5x06_ts_data *ft5x06_data = + container_of(self, struct ft5x06_ts_data, fb_notif); + #endif + #if 0 + if(is_upgrading == 1) + return 0; + #endif + if (evdata && evdata->data && event == FB_EVENT_BLANK ) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + msg21xx_resume(); + else if (*blank == FB_BLANK_POWERDOWN) + msg21xx_suspend(); + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) + +//--------------------------------------------------------------------------- +static void msg21xx_early_suspend(struct early_suspend *h) +{ + printk("Enter %s \n",__func__);; + msg21xx_suspend(); + printk("TP exit %s \n",__func__); +} + +static void msg21xx_early_resume(struct early_suspend *h) +{ + + printk("Enter %s \n",__func__); + msg21xx_resume(); + printk("TP exit %s \n",__func__); +} + +#endif +#endif +//#if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) + +//#else +static void msg21xx_chip_init(void) +{ + #if 1 //defined(TYQ_TBW5913B_SUPPORT) || defined(TYQ_TBW5913C_SUPPORT) + /* After the LCD is on, power on the TP controller */ + //gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + gpio_direction_output(MSG21XX_RESET_GPIO, 1); + gpio_set_value(MSG21XX_RESET_GPIO, 1); + gpio_set_value(MSG21XX_RESET_GPIO, 0); + mdelay(50); /* Note that the RST must be in LOW 10ms at least */ + gpio_set_value(MSG21XX_RESET_GPIO, 1); + /* Enable the interrupt service thread/routine for INT after 50ms */ + mdelay(300); + //gpio_free(MSG21XX_RESET_GPIO); //add by gaohw + #else + /* After the LCD is on, power on the TP controller */ + //gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + //gpio_direction_output(MSG21XX_RESET_GPIO, 1); + gpio_direction_output(MSG21XX_RESET_GPIO, 0); + //gpio_set_value(MSG21XX_RESET_GPIO, 1); + gpio_set_value(MSG21XX_RESET_GPIO, 0); + mdelay(200); /* Note that the RST must be in LOW 10ms at least */ + //gpio_set_value(MSG21XX_RESET_GPIO, 1); + gpio_direction_input(MSG21XX_RESET_GPIO); + /* Enable the interrupt service thread/routine for INT after 50ms */ + mdelay(50); + //gpio_free(MSG21XX_RESET_GPIO); //add by gaohw + #endif +} +//#endif + +static u8 Calculate_8BitsChecksum( u8 *msg, s32 s32Length ) +{ + s32 s32Checksum = 0; + s32 i; + + for ( i = 0 ; i < s32Length; i++ ) + { + s32Checksum += msg[i]; + } + + return (u8)( ( -s32Checksum ) & 0xFF ); +} + + +#ifdef AUTO_UPDATE +#define MSG_FW_NAME "zw2351_msg21xx.bin" + +static void msg21xx_data_disposal_gao(struct work_struct *work) +{ + const struct firmware *fw_entry = NULL; + int retval =0; + int i =0; + const unsigned char *fw_image; + unsigned long ulVer; + unsigned short update_bin_major = 0; + unsigned short update_bin_minor = 0; + + bFwUpdating = 1; + if((msg21xx_irq)&&(test_and_clear_bit(0,&mstar_tp_status.irqen))) //gaohw + disable_irq_nosync(msg21xx_irq); + + retval = fts_GetFWVer(&ulVer); + if(0 > retval) + { + printk("%s:FT_GetFWVer failed. \n",__func__); + bFwUpdating = 0; + if((msg21xx_irq)&&(!test_and_set_bit(0,&mstar_tp_status.irqen))) //add by gaohw + enable_irq(msg21xx_irq); + + return ; + } + + retval = request_firmware(&fw_entry,MSG_FW_NAME,&msg21xx_i2c_client->dev); + if (retval != 0) { + pr_info("requset firmware failed filename is %s ,ret = %d\n",MSG_FW_NAME,retval); + goto exit; + } + + TP_DEBUG("%s: Firmware image size = %d\n",__func__, fw_entry->size); + + fw_image = fw_entry->data; + + update_bin_major = fw_image[0x7f4f]<<8|fw_image[0x7f4e]; + update_bin_minor = fw_image[0x7f51]<<8|fw_image[0x7f50]; + printk("update_bin_major =%d update_bin_minor =%d\n",update_bin_major,update_bin_minor); + + + fm_major_version = fw_image[0x3077] + (fw_image[0x3076] << 8);//0x7f4d-0x7f50 + fm_minor_version = fw_image[0x3075] + (fw_image[0x3074] << 8); + mdelay(100); + firmware_version_store(firmware_cmd_dev,0,0,(size_t)i); + printk("fw_version =%s major_version =%d minor_version =%d fm_major_version =%d fm_minor_version=%d\n", fw_version,major_version,minor_version,fm_major_version,fm_minor_version); + if((major_version == fm_major_version) &&(minor_version < fm_minor_version)) + { + for(i=0;i<94;i++) + { + firmware_data_store(firmware_cmd_dev,0,fw_image+(i*1024),(size_t)i); + } + firmware_update_store(firmware_cmd_dev,0,0,(size_t)i); + printk("Update firmware successed !!!\n"); + } + else + { + printk("No nedd to update firmware\n"); + } + bFwUpdating = 0; + if((msg21xx_irq)&&(!test_and_set_bit(0,&mstar_tp_status.irqen))) //add by gaohw + enable_irq(msg21xx_irq); + + exit: + if (fw_entry) + release_firmware(fw_entry); + +} +#endif + + +static void msg21xx_data_disposal(struct work_struct *work) +{ + u8 val[8] = {0}; + u8 Checksum = 0; + u8 i; + u32 delta_x = 0, delta_y = 0; + u32 u32X = 0; + u32 u32Y = 0; + u8 touchkeycode = 0; + TouchScreenInfo_t *touchData=NULL; + static u32 preKeyStatus=0; + //static u32 preFingerNum=0; + +/*#define SWAP_X_Y (1) +#ifdef SWAP_X_Y + int tempx; + int tempy; +#endif +*/ + touchData = kzalloc(sizeof(TouchScreenInfo_t), GFP_KERNEL); + + /* tianyu quhl add 2012-10-19 */ + if(touchData==NULL) + { + printk("=====%s:request memory failed!!!!=====\n",__func__); + return; + } + memset(touchData, 0, sizeof(TouchScreenInfo_t)); + + //_TRACE((TSCR_LEVEL_C_TYP, "DrvTscrCGetData in")); + i2c_master_recv(msg21xx_i2c_client,&val[0],REPORT_PACKET_LENGTH); + Checksum = Calculate_8BitsChecksum(&val[0], 7); //calculate checksum + + + //printk("primary:: val[0]=%d,val[1]=%d,val[2]=%d,val[3]=%d,val[4]=%d,val[5]=%d,val[6]=%d,val[7]=%d\n",val[0],val[1],val[2],val[3],val[4],val[5],val[6],val[7]); + if ((Checksum == val[7]) && (val[0] == 0x52)) //check the checksum of packet + { + u32X = (((val[1] & 0xF0) << 4) | val[2]); //parse the packet to coordinates + u32Y = (((val[1] & 0x0F) << 8) | val[3]); + + delta_x = (((val[4] & 0xF0) << 4) | val[5]); + delta_y = (((val[4] & 0x0F) << 8) | val[6]); + pr_debug("primary:: u32X=%d,u32Y=%d,dx=%d,dy=%d\n",u32X,u32Y,delta_x,delta_y); +/* #ifdef SWAP_X_Y + tempy = u32X; + tempx = u32Y; + u32X = tempx; + u32Y = tempy; + + tempy = delta_x; + tempx = delta_y; + delta_x = tempx; + delta_y = tempy; + #endif +*/ + //DBG("[HAL] u32X = %x, u32Y = %x", u32X, u32Y); + //DBG("[HAL] delta_x = %x, delta_y = %x", delta_x, delta_y); + + if ((val[1] == 0xFF) && (val[2] == 0xFF) && (val[3] == 0xFF) && (val[4] == 0xFF) && (val[6] == 0xFF)) + { + touchData->Point[0].X = 0; // final X coordinate + touchData->Point[0].Y = 0; // final Y coordinate + + /* if (val[5] != 0x0) + { + touchData->nTouchKeyMode = 1; //TouchKeyMode + touchData->nTouchKeyCode = val[5]; //TouchKeyCode + touchData->nFingerNum = 1; + } + else + { + touchData->nFingerNum = 0; //touch end + touchData->nTouchKeyCode = 0; //TouchKeyMode + touchData->nTouchKeyMode = 0; //TouchKeyMode + }*/ + + if((val[5]==0x0)||(val[5]==0xFF)) + { + touchData->nFingerNum = 0; //touch end + touchData->nTouchKeyCode = 0; //TouchKeyMode + touchData->nTouchKeyMode = 0; //TouchKeyMode + } + else + { + touchData->nTouchKeyMode = 1; //TouchKeyMode + touchData->nTouchKeyCode = val[5]; //TouchKeyCode + touchData->nFingerNum = 1; + pr_debug("&&&&&&&&useful key code report touch key code = %d\n",touchData->nTouchKeyCode); + } + + + } + else + { + touchData->nTouchKeyMode = 0; //Touch on screen... + + if ((delta_x == 0) && (delta_y == 0)) + { + touchData->nFingerNum = 1; //one touch + touchData->Point[0].X = (u32X * MS_TS_MSG21XX_X_MAX) / 2048; + touchData->Point[0].Y = (u32Y * MS_TS_MSG21XX_Y_MAX ) / 2048;//1781; + + /* Calibrate if the touch panel was reversed in Y */ + #if 0 + touchData->Point[0].Y = (MS_TS_MSG21XX_Y_MAX - touchData->Point[0].Y); + #endif + } + else + { + u32 x2, y2; + + touchData->nFingerNum = 2; //two touch + + /* Finger 1 */ + touchData->Point[0].X = (u32X * MS_TS_MSG21XX_X_MAX) / 2048; + touchData->Point[0].Y = (u32Y * MS_TS_MSG21XX_Y_MAX ) / 2048;//1781; + + /* Finger 2 */ + if (delta_x > 2048) //transform the unsigh value to sign value + { + delta_x -= 4096; + } + if (delta_y > 2048) + { + delta_y -= 4096; + } + + x2 = (u32)(u32X + delta_x); + y2 = (u32)(u32Y + delta_y); + + touchData->Point[1].X = (x2 * MS_TS_MSG21XX_X_MAX) / 2048; + touchData->Point[1].Y = (y2 * MS_TS_MSG21XX_Y_MAX ) /2048;// 1781; + + /* Calibrate if the touch panel was reversed in Y */ + #if 0 + touchData->Point[1].Y = (MS_TS_MSG21XX_Y_MAX - y2); + #endif + } + } + + //report... + if(touchData->nTouchKeyMode) + { + + if (touchData->nTouchKeyCode == 2) + #ifdef TYQ_TP_ANDROID4_0_SUPPORT + touchkeycode = KEY_HOMEPAGE; + #else + touchkeycode = KEY_HOME; + #endif + if (touchData->nTouchKeyCode == 1) + touchkeycode = KEY_MENU; + if (touchData->nTouchKeyCode == 4) + touchkeycode = KEY_BACK; + #if 0 + if (touchData->nTouchKeyCode == 8) + touchkeycode = KEY_SEARCH; + #endif + if(preKeyStatus!=touchkeycode) + { + preKeyStatus=touchkeycode; + //input_report_key(input, touchkeycode, 1); + pr_debug("&&&&&&&&useful key code report touch key code = %d\n",touchkeycode); + #ifdef TYQ_TP_ANDROID4_0_SUPPORT + if(touchkeycode == KEY_HOMEPAGE) + #else + if(touchkeycode == KEY_HOME) + #endif + { + //input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, 120); + input_report_abs(input, ABS_MT_POSITION_Y, 530); + input_mt_sync(input); + + } + + if(touchkeycode == KEY_MENU) + { + // input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, 200); + input_report_abs(input, ABS_MT_POSITION_Y, 530); + input_mt_sync(input); + + } + + if(touchkeycode == KEY_BACK) + { + // input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, 40); + input_report_abs(input, ABS_MT_POSITION_Y, 530); + input_mt_sync(input); + + } + #if 0 + if(touchkeycode == KEY_SEARCH) + { + // input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, 420); + input_report_abs(input, ABS_MT_POSITION_Y, 863); + input_mt_sync(input); + + } + #endif + + } + + input_sync(input); + } + else + { + preKeyStatus=0; //clear key status.. + + if((touchData->nFingerNum) == 0) //touch end + { + //preFingerNum=0; + /* input_report_key(input, KEY_MENU, 0); + input_report_key(input, KEY_HOME, 0); + input_report_key(input, KEY_BACK, 0); + input_report_key(input, KEY_SEARCH, 0); + */ + // input_report_abs(input, ABS_MT_TOUCH_MAJOR, 0); + input_mt_sync(input); + input_sync(input); + } + else //touch on screen + { + /* + if(preFingerNum!=touchData->nFingerNum) //for one touch <--> two touch issue + { + pr_debug("langwenlong number has changed\n"); + preFingerNum=touchData->nFingerNum; + input_report_abs(input, ABS_MT_TOUCH_MAJOR, 0); + input_mt_sync(input); + input_sync(input); + }*/ + + for(i = 0;i < (touchData->nFingerNum);i++) + { + // input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input, ABS_MT_POSITION_X, touchData->Point[i].X); + input_report_abs(input, ABS_MT_POSITION_Y, touchData->Point[i].Y); + input_mt_sync(input); + pr_debug("X=%d,Y=%d\n",touchData->Point[i].X,touchData->Point[i].Y); + } + + input_sync(input); + } + } + } + else + { + //DBG("Packet error 0x%x, 0x%x, 0x%x", val[0], val[1], val[2]); + //DBG(" 0x%x, 0x%x, 0x%x", val[3], val[4], val[5]); + //DBG(" 0x%x, 0x%x, 0x%x", val[6], val[7], Checksum); + printk(KERN_ERR "err status in tp\n"); + } + if((msg21xx_irq)&&(!test_and_set_bit(0,&mstar_tp_status.irqen))) //add by gaohw + enable_irq(msg21xx_irq); + // enable_irq(msg21xx_irq); + + //tianyu quhl add 2012-10-19 + if(touchData) + { + kfree(touchData); + } +} + + + +static int msg21xx_ts_open(struct input_dev *dev) +{ + return 0; +} + +static void msg21xx_ts_close(struct input_dev *dev) +{ + printk("msg21xx_ts_close\n"); +} + + +static int msg21xx_init_input(void) +{ + int err; + + input = input_allocate_device(); + input->name ="ms-msg21xx"; + input->phys = "I2C"; + input->id.bustype = BUS_I2C; + input->dev.parent = &msg21xx_i2c_client->dev; + input->open = msg21xx_ts_open; + input->close = msg21xx_ts_close; + + set_bit(EV_ABS, input->evbit); + set_bit(EV_SYN, input->evbit); + set_bit(EV_KEY, input->evbit); // zhangzhao add for fastmmi + + #ifdef TYQ_TP_ANDROID4_0_SUPPORT + set_bit(INPUT_PROP_DIRECT,input->propbit); + #else + set_bit(EV_KEY, input->evbit); + set_bit(BTN_TOUCH, input->keybit); + #endif + set_bit(KEY_BACK, input->keybit); + set_bit(KEY_MENU, input->keybit); + #ifdef TYQ_TP_ANDROID4_0_SUPPORT + set_bit(KEY_HOMEPAGE, input->keybit); + #else + set_bit(KEY_HOME, input->keybit); + #endif + //set_bit(KEY_SEARCH, input->keybit); + +// input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, 0, MS_TS_MSG21XX_X_MAX, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, MS_TS_MSG21XX_Y_MAX, 0, 0); + + err = input_register_device(input); + if (err) + goto fail_alloc_input; + +fail_alloc_input: + return 0; +} +static irqreturn_t msg21xx_interrupt(int irq, void *dev_id) +{ + if((msg21xx_irq)&&(test_and_clear_bit(0,&mstar_tp_status.irqen))) //gaohw + disable_irq_nosync(msg21xx_irq); + schedule_work(&msg21xx_wq); + return IRQ_HANDLED; +} + + +static int __devinit msg21xx_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + #ifdef AUTO_UPDATE +// int i = 0; + #endif + #if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) + u8 val[9] = {0}; + if(ft_probe_flag ==1) + return -1; + #endif + msg21xx_i2c_client = client; + #if defined TY_PMU_CTL + err = mstar_power_init(); + if (err) { + dev_err(&client->dev, "Mstar power init failed\n"); + //goto exit_free_client_data; + } + + err = mstar_power_on(); + if (err) { + dev_err(&client->dev, "Mstar power on failed\n"); + //goto exit_deinit_power; + } + #endif + printk("haoweiwei in msg probe\n"); + gpio_request(MSG21XX_RESET_GPIO, "reset"); //add by gaohw + gpio_request(MSG21XX_INT_GPIO, "interrupt"); +// gpio_request(MSG21XX_RESET_GPIO, "reset"); + gpio_direction_input(MSG21XX_INT_GPIO); + //gpio_free(MSG21XX_INT_GPIO); //add by gaohw +// gpio_set_value(MSG21XX_INT_GPIO, 1); +//#if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) + // tp have been reseted in board-7x27a.c +//#else + msg21xx_chip_init(); +//#endif + #if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) + //msleep(200); + //printk("********************msg21xx_probe********************************\n"); + err = i2c_master_recv(msg21xx_i2c_client,&val[0],REPORT_PACKET_LENGTH); + if(err < 0) + { + printk("Mstar tp detected failure!\n"); + goto exit0; + } + #endif + #if 1 + chip_id=get_chip_id(); + printk("mstar chip id = %x\n",chip_id); + msg21xx_chip_init(); + #endif + INIT_WORK(&msg21xx_wq, msg21xx_data_disposal); + + #ifdef AUTO_UPDATE + INIT_WORK(&msg21xx_wq_gao, msg21xx_data_disposal_gao); + #endif + + msg21xx_init_input(); + msg21xx_irq = client->irq; //gaohw + set_bit(0,&mstar_tp_status.irqen); //add by gaohw + err = request_irq(msg21xx_irq, msg21xx_interrupt, + IRQF_TRIGGER_RISING, "msg21xx", NULL); //gaohw no modify + if (err != 0) { + printk("%s: cannot register irq\n", __func__); + goto exit; + } + #if defined(CONFIG_FB) + fb_notif.notifier_call = fb_notifier_callback; + + err = fb_register_client(&fb_notif); + + if (err) + dev_err(&client->dev, "Unable to register fb_notifier: %d\n",err); + + #elif defined(CONFIG_HAS_EARLYSUSPEND) + early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +1; //gao +1? + early_suspend.suspend = msg21xx_early_suspend; + early_suspend.resume = msg21xx_early_resume; + register_early_suspend(&early_suspend); + #endif + +#ifdef TYN_VIRTAUL_KEY_FRAMEWORK + fts_creat_virtual_key_sysfs(); //add by gaohw +#endif + /*frameware upgrade*/ +#ifdef __FIRMWARE_UPDATE__ + touch_ctrl_init(0); + firmware_class = class_create(THIS_MODULE, "ms-touchscreen-msg20xx"); + if (IS_ERR(firmware_class)) + pr_err("Failed to create class(firmware)!\n"); + firmware_cmd_dev = device_create(firmware_class, + NULL, 0, NULL, "device"); + if (IS_ERR(firmware_cmd_dev)) + pr_err("Failed to create device(firmware_cmd_dev)!\n"); + + // version + if (device_create_file(firmware_cmd_dev, &dev_attr_version) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_version.attr.name); + // update + if (device_create_file(firmware_cmd_dev, &dev_attr_update) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_update.attr.name); + // data + if (device_create_file(firmware_cmd_dev, &dev_attr_data) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_data.attr.name); + // clear + if (device_create_file(firmware_cmd_dev, &dev_attr_clear) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_clear.attr.name); + + dev_set_drvdata(firmware_cmd_dev, NULL); +#endif + +#ifdef AUTO_UPDATE +_msg_auto_updateFirmware(); +#if 0 + #ifndef __MSG_2133_BIN__ + #else + fm_major_version = MSG_2133_BIN[0x7f50] + (MSG_2133_BIN[0x7f4f] << 8);//0x7f4d-0x7f50 + fm_minor_version = MSG_2133_BIN[0x7f4e] + (MSG_2133_BIN[0x7f4d] << 8); + mdelay(100); + firmware_version_store(firmware_cmd_dev,0,0,(size_t)i); + printk("fw_version =%s major_version =%d minor_version =%d fm_major_version =%d fm_minor_version=%d\n", fw_version,major_version,minor_version,fm_major_version,fm_minor_version); + if((major_version == fm_major_version) &&(minor_version < fm_minor_version)) +// if(fw_version[2]!=0x31 && fw_version[4]!=0x31 && fw_version[5]!=0x31) + { + schedule_work(&msg21xx_wq_gao); + /*TP_DEBUG("current fw_version is %s,wrong version !! \n",fw_version); + for(i=0;i<94;i++) + { + firmware_data_store(firmware_cmd_dev,0,MSG_2133_BIN+(i*1024),(size_t)i); + } + firmware_update_store(firmware_cmd_dev,0,0,(size_t)i); + */ + } + else + { + TP_DEBUG("firmware version check okay, no need update \n"); + } + + //mdelay(10000); +#endif +#endif +#endif + + return 0; + +#if defined(CONFIG_TOUCHSCREEN_FT5X06) && defined(CONFIG_TY_TOUCHSCREEN_MSTAR) +exit0: + gpio_free(MSG21XX_RESET_GPIO); + gpio_free(MSG21XX_INT_GPIO); +#endif + +exit: + return err; +} + + +/*******************************start irmware updae control*******************************/ + +static int touch_ctrl_open(struct inode *inode, struct file *filp) +{ + printk("%s\n", __func__); + return 0; +} + +static ssize_t touch_ctrl_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + printk("%s, calibration %s %d\n", __func__, buf, count); + + //NvOdmTouchSetAutoCalibration(touch_context->hTouchDevice, FTS_TRUE); + return 0; +} +static ssize_t touch_ctrl_read (struct file *file, char *buf, size_t count, loff_t *offset) +{ + printk("touch_ctrl_read calibration\n"); + return 0; +} + +static long touch_ctrl_ioctl(struct file * file, unsigned int cmd, unsigned long arg) +{ + struct ty_touch_fmupgrade_S bufarg; + int iret; + unsigned char *pBuf; + u8 bRet = 0; + unsigned long ulVer; + //unsigned long i; + int mVer; + + if (0 == arg) + { + printk("%s:arg null pointer.\n",__func__); + return -EFAULT; + } + + if (copy_from_user(&bufarg, (void *) arg, sizeof(bufarg))) + { + printk("%s:null pointer.\n",__func__); + return -EFAULT; + } + + printk("%s:cmd=0x%x.\n",__func__,cmd); + + switch (cmd) + { + case TYN_TOUCH_FWVER: + printk("%s:getver.\n",__func__); + if (NULL == bufarg.bufAddr) + { + printk("%s:bufAddr null pointer.\n",__func__); + return -EFAULT; + } + printk("%s:getver 1.\n",__func__); + + if ((0>= bufarg.bufLength )||( sizeof(unsigned long) < bufarg.bufLength )) + { + printk("%s:bufLength null pointer.\n",__func__); + return -EFAULT; + } + //printk("%s:lenth=%x,addr=0x%x\n",__func__,(unsigned int)bufarg.bufLength,(bufarg.bufAddr)); + printk("%s:getver 2\n",__func__); + + pBuf = kzalloc(bufarg.bufLength, GFP_KERNEL); + if (0 == pBuf) + { + printk("%s:alloc buffer failed.\n",__func__); + return 0; + } + + if (copy_from_user(pBuf, (void *)bufarg.bufAddr, bufarg.bufLength)) + { + printk("%s:get buffer error.\n",__func__); + return -EFAULT; + } + printk("%s:getver 3.\n",__func__); + + + ulVer = 0; + + //get firmware version + #if defined(NV_TOUCH_FT) + mdelay(200); + bRet = fts_GetFWVer(&ulVer); + if(0 > bRet) + { + *(unsigned long*)bufarg.bufAddr = 0; + printk("%s:FT_GetFWVer failed. \n",__func__); + kfree(pBuf); + return -EFAULT; + } + #endif + + *(( unsigned long *)bufarg.bufAddr) = ulVer; + + //printk("%s:ver=0x%x \n",__func__,*(unsigned long*)bufarg.bufAddr); + if( pBuf ) kfree(pBuf); + + break; + case TYN_TOUCH_CHIPID: + printk("%s:getchipidr.\n",__func__); + if (NULL == bufarg.bufAddr) + { + printk("%s:bufAddr null pointer.\n",__func__); + return -EFAULT; + } + printk("%s:getver 1.\n",__func__); + + if ((0>= bufarg.bufLength )||( sizeof(unsigned long) < bufarg.bufLength )) + { + printk("%s:bufLength null pointer.\n",__func__); + return -EFAULT; + } + //printk("%s:lenth=%x,addr=0x%x\n",__func__,(unsigned int)bufarg.bufLength,(bufarg.bufAddr)); + printk("%s:getver 2\n",__func__); + + pBuf = kzalloc(bufarg.bufLength, GFP_KERNEL); + if (0 == pBuf) + { + printk("%s:alloc buffer failed.\n",__func__); + return 0; + } + + if (copy_from_user(pBuf, (void *)bufarg.bufAddr, bufarg.bufLength)) + { + printk("%s:get buffer error.\n",__func__); + return -EFAULT; + } + printk("%s:getver 3.\n",__func__); + + + + *(( unsigned long *)bufarg.bufAddr) = (unsigned long)chip_id; + + //printk("%s:ver=0x%x \n",__func__,*(unsigned long*)bufarg.bufAddr); + if( pBuf ) kfree(pBuf); + + break; + + case TYN_TOUCH_FMUPGRADE: + if (0 == bufarg.bufAddr) + { + printk("%s:null pointer.\n",__func__); + return 0; + } + + pBuf =&temp[0][0]; //kzalloc(bufarg.bufLength, GFP_KERNEL); + if (0 == pBuf) + { + printk("%s:alloc buffer failed.\n",__func__); + return 0; + } + + if (copy_from_user(pBuf, (void *) bufarg.bufAddr, bufarg.bufLength)) + { + printk("%s:get buffer error.\n",__func__); + return -EAGAIN; + } + mdelay(200); + + + bRet = fts_GetFWVer(&ulVer); + if(0 > bRet) + { + printk("%s:FT_GetFWVer failed. \n",__func__); + return -EFAULT; + } + + /* if((ulVer >> 16) != (pBuf[0x3077] + (pBuf[0x3076] << 8))) + { + printk("%s:major_version do not match. \n",__func__); + return -EFAULT; + } + */ + //get crc and check crc + // + + //printk("%s:type=0x%x,len=0x%x \n",__func__,bufarg.touchType,bufarg.bufLength); + //printk("ver=0x%x,0x%x,0x%x \n",pBuf[bufarg.bufLength-3],pBuf[bufarg.bufLength-2],pBuf[bufarg.bufLength-1]); + + #if defined(NV_TOUCH_FT) + if( TYN_TOUCH_FOCALTECH == bufarg.touchType) + { + iret = firmware_update_store(0,0,0,0);//fts_ctpm_fw_upgrade_with_i_file(pBuf,bufarg.bufLength); + if(iret) + { + printk("update focaltech firmware failed.\n"); + } + //kfree(pBuf); + return iret; + } + #endif + // if( pBuf ) kfree(pBuf); + break; + case TYN_TOUCH_VENDOR: + ulVer = 0; + mdelay(200); + bRet = fts_GetFWVer(&ulVer); + if(0 > bRet) + { + printk("%s:FT_GetFWVer failed. \n",__func__); + return -EFAULT; + } + + mVer=ulVer>>16; + printk("====get touch vendor :%d,%ld=========\n",mVer,ulVer); + + if((ulVer >> 16) == 6) + { + #if defined(TYQ_TBE5916_SUPPORT)||defined(TYQ_TBW5913_SUPPORT) + if(copy_to_user(bufarg.bufAddr,"BYD_tp(ic:msg2133)",strlen("BYD_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #else + if(copy_to_user(bufarg.bufAddr,"truly_tp(ic:msg2133)",strlen("truly_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #endif + } + else if((ulVer >> 16) == 1) + { + #if defined(TYQ_TBE5916_SUPPORT)||defined(TYQ_TBW5913_SUPPORT) + if(copy_to_user(bufarg.bufAddr,"truly_tp(ic:msg2133)",strlen("truly_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #else + if(copy_to_user(bufarg.bufAddr,"unknown(ic:msg2133)",strlen("unknown(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #endif + } + else if((ulVer >> 16) == 7 ) + { + #if defined(TYQ_TBE5916_SUPPORT)||defined(TYQ_TBW5913_SUPPORT) + if(copy_to_user(bufarg.bufAddr,"truly_tp(ic:msg2133)",strlen("truly_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #else + if(copy_to_user(bufarg.bufAddr,"unknown(ic:msg2133)",strlen("unknown(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + #endif + } + else if((ulVer >> 16) == 4 ) + { + if(copy_to_user(bufarg.bufAddr,"truly_tp(ic:msg2133)",strlen("truly_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + } + else if((ulVer >> 16) == 5) + { + if(copy_to_user(bufarg.bufAddr,"lcetron_tp(ic:msg2133)",strlen("lcetron_tp(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + } + else + { + if(copy_to_user(bufarg.bufAddr,"unknown(ic:msg2133)",strlen("unknown(ic:msg2133)"))) + { + printk("%s:get tp_vendor info err!\n",__func__); + } + } + break; + default: + printk("%s:Invalid command.\n",__func__); + + } + + return 0; +} + +static int touch_ctrl_close(struct inode *inode, struct file *filp) +{ + printk("%s\n", __func__); + return 0; +} + +struct file_operations ty_touch_ctrl_fops_msg = +{ + .write = touch_ctrl_write, + .read = touch_ctrl_read, + .open = touch_ctrl_open, + .release = touch_ctrl_close, + .unlocked_ioctl = touch_ctrl_ioctl, +}; + +static int touch_ctrl_init(void *touch) +{ + int ret = 0; + struct device *fts_chr_device; + + ret = alloc_chrdev_region(&ty_touch_ctrl.devno, 0, 1, "touch_ctrl"); + if(ret) + { + printk("%s, can't alloc chrdev\n", __func__); + } + printk("%s, register chrdev(%d, %d)\n", __func__, MAJOR(ty_touch_ctrl.devno), MINOR(ty_touch_ctrl.devno)); + + cdev_init(&ty_touch_ctrl.cdev, &ty_touch_ctrl_fops_msg); + + ty_touch_ctrl.cdev.owner = THIS_MODULE; + ty_touch_ctrl.cdev.ops = &ty_touch_ctrl_fops_msg; + + ret = cdev_add(&ty_touch_ctrl.cdev, ty_touch_ctrl.devno, 1); + if(ret < 0) + { + printk("%s, add char devive error, ret %d\n", __func__, ret); + } + + ty_touch_ctrl.class = class_create(THIS_MODULE, "fts_touch_ctrl"); + if(IS_ERR(ty_touch_ctrl.class)){ + printk("%s, creating class error\n", __func__); + } + + fts_chr_device=device_create(ty_touch_ctrl.class, NULL, ty_touch_ctrl.devno, NULL, "fts_fw_entry"); + if(NULL == fts_chr_device){ + printk("%s, create device, error\n", __func__); + class_destroy(ty_touch_ctrl.class); + } + + return (int)touch; +} + + +/*******************************end irmware updae*******************************/ + + +static int __devexit msg21xx_remove(struct i2c_client *client) +{ + #if defined TY_PMU_CTL + mstar_power_off(); + mstar_power_deinit(); + #endif + return 0; +} + + + +static const struct i2c_device_id msg21xx_id[] = { + { "ms-msg21xx", 0x26 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, msg21xx_id); + +static struct of_device_id mstar_match_table[] = { + { .compatible = "mstar,ms-msg21xx", }, + { }, +}; + + +static struct i2c_driver msg21xx_driver = { + .driver = { + .name = "ms-msg21xx", + .owner = THIS_MODULE, + .of_match_table = mstar_match_table, + }, + .probe = msg21xx_probe, + .remove = __devexit_p(msg21xx_remove), + .id_table = msg21xx_id, +}; + + + + + +static int __init msg21xx_init(void) +{ + int err; + err = i2c_add_driver(&msg21xx_driver); + if (err) { + printk(KERN_WARNING "msg21xx driver failed " + "(errno = %d)\n", err); + } else { + printk( "Successfully added driver %s\n", + msg21xx_driver.driver.name); + } + return err; +} + +static void __exit msg21xx_cleanup(void) +{ + i2c_del_driver(&msg21xx_driver); +} + + +module_init(msg21xx_init); +module_exit(msg21xx_cleanup); + +MODULE_AUTHOR("Mstar semiconductor"); +MODULE_DESCRIPTION("Driver for msg21xx Touchscreen Controller"); +MODULE_LICENSE("GPL"); + From 3fd39dfb8b83804556f0d89b00b9a049555c721e Mon Sep 17 00:00:00 2001 From: Brinly Taylor Date: Thu, 26 Nov 2015 13:53:34 +1030 Subject: [PATCH 6/6] asm: msm: Add T792 specific battery-data We unfortunately use a 1200mah battery so we can't use the Open C version. --- arch/arm/mach-msm/Makefile | 4 +- .../bms_batterydata_4v2_524846_t972.c | 109 ++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/bms_batterydata_4v2_524846_t972.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index e697cc0a3620..2f57ce4cd24a 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -261,8 +261,10 @@ obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o -obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o bms_batterydata_4v2_554846.o bms_batterydata_4v2_524846.o +obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o bms_batterydata_4v2_554846.o obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o bms-batterydata-qrd-4v2-1300mah.o +obj-$(CONFIG_BATT_ZTE_4V2_554846) += bms_batterydata_4v2_524846.o +obj-$(CONFIG_BATT_ZTE_4V2_554846_T792) += bms_batterydata_4v2_524846_t792.o obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o diff --git a/arch/arm/mach-msm/bms_batterydata_4v2_524846_t972.c b/arch/arm/mach-msm/bms_batterydata_4v2_524846_t972.c new file mode 100644 index 000000000000..4fa747ee06dc --- /dev/null +++ b/arch/arm/mach-msm/bms_batterydata_4v2_524846_t972.c @@ -0,0 +1,109 @@ +/******************************************************************** +who: ZTEBSP doumingming +when: 20131223 +what: add bms battery data for 554846 battery cells +notice: there is a macro for every battery data, + eg: CONFIG_BATT_ZTE_4V2_554846_T792 +********************************************************************/ +#include + +static struct single_row_lut fcc_temp = { + .x = {-20, 0, 25, 40, 60}, + .y = {1505, 1509, 1511, 1512, 1510}, + .cols = 5 +}; + +static struct single_row_lut fcc_sf = { + .x = {0}, + .y = {100}, + .cols = 1 +}; + +static struct sf_lut rbatt_sf = { + .rows = 31, + .cols = 5, + .row_entries = {-20, 0, 25, 40, 60}, + .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 16, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + .sf = { + {553, 177, 100, 90, 85}, + {579, 183, 100, 91, 85}, + {636, 209, 104, 92, 86}, + {617, 207, 106, 94, 87}, + {630, 208, 110, 96, 89}, + {628, 213, 113, 99, 91}, + {632, 203, 119, 103, 94}, + {640, 192, 125, 108, 97}, + {652, 189, 126, 113, 102}, + {669, 188, 106, 101, 96}, + {691, 194, 100, 91, 86}, + {723, 203, 103, 93, 87}, + {762, 220, 108, 98, 92}, + {810, 251, 118, 105, 97}, + {839, 271, 122, 105, 95}, + {846, 259, 114, 98, 91}, + {992, 267, 112, 97, 90}, + {1534, 286, 113, 98, 90}, + {2585, 317, 112, 97, 89}, + {3919, 373, 115, 98, 91}, + {4990, 421, 119, 101, 93}, + {6415, 489, 123, 104, 94}, + {8386, 597, 128, 106, 96}, + {11088, 738, 134, 109, 96}, + {14798, 970, 140, 111, 95}, + {19935, 1387, 142, 109, 94}, + {26957, 1923, 150, 111, 96}, + {36179, 2675, 165, 117, 98}, + {48041, 3741, 196, 126, 103}, + {61480, 5207, 256, 141, 111}, + {73273, 7457, 745, 215, 189} + } +}; + +static struct pc_temp_ocv_lut pc_temp_ocv = { + .rows = 31, + .cols = 5, + .temp = {-20, 0, 25, 40, 60}, + .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 16, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + .ocv = { + {4170, 4161, 4164, 4157, 4157}, + {4096, 4101, 4103, 4098, 4097}, + {4025, 4048, 4053, 4048, 4046}, + {3953, 3985, 3998, 3999, 4000}, + {3919, 3950, 3962, 3960, 3958}, + {3881, 3917, 3925, 3922, 3921}, + {3847, 3875, 3892, 3889, 3887}, + {3820, 3835, 3861, 3859, 3857}, + {3801, 3807, 3832, 3832, 3830}, + {3789, 3790, 3795, 3797, 3797}, + {3778, 3784, 3778, 3775, 3771}, + {3764, 3781, 3775, 3771, 3764}, + {3744, 3775, 3772, 3768, 3762}, + {3711, 3760, 3765, 3762, 3757}, + {3669, 3718, 3734, 3731, 3730}, + {3619, 3653, 3670, 3666, 3663}, + {3567, 3593, 3610, 3609, 3606}, + {3529, 3543, 3561, 3563, 3561}, + {3501, 3516, 3525, 3525, 3525}, + {3481, 3503, 3512, 3514, 3514}, + {3468, 3497, 3507, 3508, 3509}, + {3455, 3490, 3502, 3503, 3503}, + {3438, 3483, 3495, 3497, 3497}, + {3417, 3474, 3488, 3489, 3489}, + {3390, 3459, 3476, 3477, 3474}, + {3358, 3429, 3447, 3447, 3441}, + {3318, 3386, 3400, 3400, 3393}, + {3268, 3331, 3340, 3341, 3334}, + {3204, 3257, 3264, 3267, 3259}, + {3115, 3153, 3163, 3166, 3159}, + {3000, 3000, 3000, 3000, 3000} + } +}; + +struct bms_battery_data ZTE_4v2_524846_t792_data = { + .fcc = 1200, + .fcc_temp_lut = &fcc_temp, + .fcc_sf_lut = &fcc_sf, + .pc_temp_ocv_lut = &pc_temp_ocv, + .rbatt_sf_lut = &rbatt_sf, + .default_rbatt_mohm = 196 +};