summaryrefslogtreecommitdiff
path: root/drivers/input/sensor/kionix_gsensor/kionix_accel.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/input/sensor/kionix_gsensor/kionix_accel.c
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/input/sensor/kionix_gsensor/kionix_accel.c')
-rwxr-xr-xdrivers/input/sensor/kionix_gsensor/kionix_accel.c2427
1 files changed, 2427 insertions, 0 deletions
diff --git a/drivers/input/sensor/kionix_gsensor/kionix_accel.c b/drivers/input/sensor/kionix_gsensor/kionix_accel.c
new file mode 100755
index 00000000..ddb5bbcb
--- /dev/null
+++ b/drivers/input/sensor/kionix_gsensor/kionix_accel.c
@@ -0,0 +1,2427 @@
+/* drivers/input/misc/kionix_accel.c - Kionix accelerometer driver
+ *
+ * Copyright (C) 2012 Kionix, Inc.
+ * Written by Kuching Tan <kuchingtan@kionix.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+//#include <linux/input/kionix_accel.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+#include "kionix_accel.h"
+#include "../sensor.h"
+
+
+
+/* Debug Message Flags */
+#define KIONIX_KMSG_ERR 1 /* Print kernel debug message for error */
+#define KIONIX_KMSG_INF 1 /* Print kernel debug message for info */
+
+#if KIONIX_KMSG_ERR
+#define KMSGERR(format, ...) \
+ dev_err(format, ## __VA_ARGS__)
+ //printk(format, ## __VA_ARGS__)
+#else
+#define KMSGERR(format, ...)
+#endif
+
+#if KIONIX_KMSG_INF
+#define KMSGINF(format, ...) \
+ dev_info(format, ## __VA_ARGS__)
+ //printk(format, ## __VA_ARGS__)
+#else
+#define KMSGINF(format, ...)
+#endif
+
+
+/******************************************************************************
+ * Accelerometer WHO_AM_I return value
+ *****************************************************************************/
+#define KIONIX_ACCEL_WHO_AM_I_KXTE9 0x00
+#define KIONIX_ACCEL_WHO_AM_I_KXTF9 0x01
+#define KIONIX_ACCEL_WHO_AM_I_KXTI9_1001 0x04
+#define KIONIX_ACCEL_WHO_AM_I_KXTIK_1004 0x05
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005 0x07
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007 0x08
+#define KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008 0x0A
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009 0x09
+#define KIONIX_ACCEL_WHO_AM_I_KXCJK_1013 0x11
+
+/******************************************************************************
+ * Accelerometer Grouping
+ *****************************************************************************/
+#define KIONIX_ACCEL_GRP1 1 /* KXTE9 */
+#define KIONIX_ACCEL_GRP2 2 /* KXTF9/I9-1001/J9-1005 */
+#define KIONIX_ACCEL_GRP3 3 /* KXTIK-1004 */
+#define KIONIX_ACCEL_GRP4 4 /* KXTJ9-1007/KXCJ9-1008 */
+#define KIONIX_ACCEL_GRP5 5 /* KXTJ2-1009 */
+#define KIONIX_ACCEL_GRP6 6 /* KXCJK-1013 */
+
+/******************************************************************************
+ * Registers for Accelerometer Group 1 & 2 & 3
+ *****************************************************************************/
+#define ACCEL_WHO_AM_I 0x0F
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 1 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP1_XOUT 0x12
+/* Control Registers */
+#define ACCEL_GRP1_CTRL_REG1 0x1B
+/* CTRL_REG1 */
+#define ACCEL_GRP1_PC1_OFF 0x7F
+#define ACCEL_GRP1_PC1_ON (1 << 7)
+#define ACCEL_GRP1_ODR40 (3 << 3)
+#define ACCEL_GRP1_ODR10 (2 << 3)
+#define ACCEL_GRP1_ODR3 (1 << 3)
+#define ACCEL_GRP1_ODR1 (0 << 3)
+#define ACCEL_GRP1_ODR_MASK (3 << 3)
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 2 & 3 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP2_XOUT_L 0x06
+/* Control Registers */
+#define ACCEL_GRP2_INT_REL 0x1A
+#define ACCEL_GRP2_CTRL_REG1 0x1B
+#define ACCEL_GRP2_INT_CTRL1 0x1E
+#define ACCEL_GRP2_DATA_CTRL 0x21
+/* CTRL_REG1 */
+#define ACCEL_GRP2_PC1_OFF 0x7F
+#define ACCEL_GRP2_PC1_ON (1 << 7)
+#define ACCEL_GRP2_DRDYE (1 << 5)
+#define ACCEL_GRP2_G_8G (2 << 3)
+#define ACCEL_GRP2_G_4G (1 << 3)
+#define ACCEL_GRP2_G_2G (0 << 3)
+#define ACCEL_GRP2_G_MASK (3 << 3)
+#define ACCEL_GRP2_RES_8BIT (0 << 6)
+#define ACCEL_GRP2_RES_12BIT (1 << 6)
+#define ACCEL_GRP2_RES_MASK (1 << 6)
+/* INT_CTRL1 */
+#define ACCEL_GRP2_IEA (1 << 4)
+#define ACCEL_GRP2_IEN (1 << 5)
+/* DATA_CTRL_REG */
+#define ACCEL_GRP2_ODR12_5 0x00
+#define ACCEL_GRP2_ODR25 0x01
+#define ACCEL_GRP2_ODR50 0x02
+#define ACCEL_GRP2_ODR100 0x03
+#define ACCEL_GRP2_ODR200 0x04
+#define ACCEL_GRP2_ODR400 0x05
+#define ACCEL_GRP2_ODR800 0x06
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 4 & 5 & 6 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP4_XOUT_L 0x06
+/* Control Registers */
+#define ACCEL_GRP4_INT_REL 0x1A
+#define ACCEL_GRP4_CTRL_REG1 0x1B
+#define ACCEL_GRP4_INT_CTRL1 0x1E
+#define ACCEL_GRP4_DATA_CTRL 0x21
+/* CTRL_REG1 */
+#define ACCEL_GRP4_PC1_OFF 0x7F
+#define ACCEL_GRP4_PC1_ON (1 << 7)
+#define ACCEL_GRP4_DRDYE (1 << 5)
+#define ACCEL_GRP4_G_8G (2 << 3)
+#define ACCEL_GRP4_G_4G (1 << 3)
+#define ACCEL_GRP4_G_2G (0 << 3)
+#define ACCEL_GRP4_G_MASK (3 << 3)
+#define ACCEL_GRP4_RES_8BIT (0 << 6)
+#define ACCEL_GRP4_RES_12BIT (1 << 6)
+#define ACCEL_GRP4_RES_MASK (1 << 6)
+/* INT_CTRL1 */
+#define ACCEL_GRP4_IEA (1 << 4)
+#define ACCEL_GRP4_IEN (1 << 5)
+/* DATA_CTRL_REG */
+#define ACCEL_GRP4_ODR0_781 0x08
+#define ACCEL_GRP4_ODR1_563 0x09
+#define ACCEL_GRP4_ODR3_125 0x0A
+#define ACCEL_GRP4_ODR6_25 0x0B
+#define ACCEL_GRP4_ODR12_5 0x00
+#define ACCEL_GRP4_ODR25 0x01
+#define ACCEL_GRP4_ODR50 0x02
+#define ACCEL_GRP4_ODR100 0x03
+#define ACCEL_GRP4_ODR200 0x04
+#define ACCEL_GRP4_ODR400 0x05
+#define ACCEL_GRP4_ODR800 0x06
+#define ACCEL_GRP4_ODR1600 0x07
+/*****************************************************************************/
+
+/* Input Event Constants */
+#define ACCEL_G_MAX 8096
+#define ACCEL_FUZZ 3
+#define ACCEL_FLAT 3
+/* I2C Retry Constants */
+#define KIONIX_I2C_RETRY_COUNT 10 /* Number of times to retry i2c */
+#define KIONIX_I2C_RETRY_TIMEOUT 1 /* Timeout between retry (miliseconds) */
+
+/* Earlysuspend Contants */
+#define KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT 5000 /* Timeout (miliseconds) */
+
+/*
+ * The following table lists the maximum appropriate poll interval for each
+ * available output data rate (ODR).
+ */
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp1_odr_table[] = {
+ { 100, ACCEL_GRP1_ODR40 },
+ { 334, ACCEL_GRP1_ODR10 },
+ { 1000, ACCEL_GRP1_ODR3 },
+ { 0, ACCEL_GRP1_ODR1 },
+};
+
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp2_odr_table[] = {
+ { 3, ACCEL_GRP2_ODR800 },
+ { 5, ACCEL_GRP2_ODR400 },
+ { 10, ACCEL_GRP2_ODR200 },
+ { 20, ACCEL_GRP2_ODR100 },
+ { 40, ACCEL_GRP2_ODR50 },
+ { 80, ACCEL_GRP2_ODR25 },
+ { 0, ACCEL_GRP2_ODR12_5},
+};
+
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp4_odr_table[] = {
+ { 2, ACCEL_GRP4_ODR1600 },
+ { 3, ACCEL_GRP4_ODR800 },
+ { 5, ACCEL_GRP4_ODR400 },
+ { 10, ACCEL_GRP4_ODR200 },
+ { 20, ACCEL_GRP4_ODR100 },
+ { 40, ACCEL_GRP4_ODR50 },
+ { 80, ACCEL_GRP4_ODR25 },
+ { 160, ACCEL_GRP4_ODR12_5},
+ { 320, ACCEL_GRP4_ODR6_25},
+ { 640, ACCEL_GRP4_ODR3_125},
+ { 1280, ACCEL_GRP4_ODR1_563},
+ { 0, ACCEL_GRP4_ODR0_781},
+};
+
+enum {
+ accel_grp1_ctrl_reg1 = 0,
+ accel_grp1_regs_count,
+};
+
+enum {
+ accel_grp2_ctrl_reg1 = 0,
+ accel_grp2_data_ctrl,
+ accel_grp2_int_ctrl,
+ accel_grp2_regs_count,
+};
+
+enum {
+ accel_grp4_ctrl_reg1 = 0,
+ accel_grp4_data_ctrl,
+ accel_grp4_int_ctrl,
+ accel_grp4_regs_count,
+};
+
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define GSENSOR_MAJOR 161
+static struct i2c_client *this_client = NULL;
+static struct platform_device *this_pdev;
+static struct kionix_accel_platform_data kionix_accel_pdata = {
+ .min_interval = 5,
+ .poll_interval = 200,
+ .accel_direction = 7,
+ .accel_irq_use_drdy = 0,
+ .accel_res = KIONIX_ACCEL_RES_12BIT,
+ .accel_g_range = KIONIX_ACCEL_G_4G,
+};
+/*
+struct kionix_config
+{
+ int op;
+ int int_gpio; //0-3
+ int xyz_axis[3][2]; // (axis,direction)
+ int rxyz_axis[3][2];
+ int irq;
+ struct proc_dir_entry* sensor_proc;
+ int sensorlevel;
+ int shake_enable; // 1--enable shake, 0--disable shake
+ int manual_rotation; // 0--landance, 90--vertical
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg; // 0-- no debug log, 1--show debug log
+ int sensor_samp; // 1,2,4,8,16,32,64,120
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ spinlock_t spinlock;
+ int pollcnt; // the counts of polling
+ int offset[3];
+};
+
+static struct kionix_config l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .irq = 6,
+ .int_gpio = 3,
+ .sensor_proc = NULL,
+ //.sensorlevel = SENSOR_GRAVITYGAME_MODE,
+ .shake_enable = 0, // default enable shake
+ .isdbg = 0,
+ .sensor_samp = 10, // 4sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds
+ .offset = {0,0,0},
+};
+*/
+
+struct kionix_accel_driver {
+ struct i2c_client *client;
+ struct kionix_accel_platform_data accel_pdata;
+ struct input_dev *input_dev;
+ struct delayed_work accel_work;
+ struct workqueue_struct *accel_workqueue;
+ wait_queue_head_t wqh_suspend;
+
+ int accel_data[3];
+ int accel_cali[3];
+ u8 axis_map_x;
+ u8 axis_map_y;
+ u8 axis_map_z;
+ bool negate_x;
+ bool negate_y;
+ bool negate_z;
+ u8 shift;
+
+ unsigned int poll_interval;
+ unsigned int poll_delay;
+ unsigned int accel_group;
+ u8 *accel_registers;
+
+ atomic_t accel_suspended;
+ atomic_t accel_suspend_continue;
+ atomic_t accel_enabled;
+ atomic_t accel_input_event;
+ atomic_t accel_enable_resume;
+ struct mutex mutex_earlysuspend;
+ struct mutex mutex_resume;
+ struct mutex mutex_subinput;
+ rwlock_t rwlock_accel_data;
+
+ bool accel_drdy;
+
+ /* Function callback */
+ void (*kionix_accel_report_accel_data)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_update_odr)(struct kionix_accel_driver *acceld, unsigned int poll_interval);
+ int (*kionix_accel_power_on_init)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_operate)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_standby)(struct kionix_accel_driver *acceld);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static void kionix_accel_update_direction(struct kionix_accel_driver *acceld);
+static int get_axisset(struct kionix_accel_driver *acceld)
+{
+ char varbuf[64];
+ int n;
+ int ubootvar[3][3];
+ int varlen;
+ int err;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.kionixgsensor", varbuf, &varlen)) {
+ printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n");
+ return -1;
+ kionix_accel_update_direction(acceld);//return -1;
+ } else {
+ sscanf(varbuf, "%d:%d:%d:%d:%d:%d",
+ &ubootvar[0][0],
+ &ubootvar[0][1],
+ &ubootvar[1][0],
+ &ubootvar[1][1],
+ &ubootvar[2][0],
+ &ubootvar[2][1]);
+
+ acceld->axis_map_x = ubootvar[0][0];
+ acceld->negate_x = ubootvar[0][1]<0?1:0;
+ acceld->axis_map_y = ubootvar[1][0];
+ acceld->negate_y = ubootvar[1][1]<0?1:0;
+ acceld->axis_map_z = ubootvar[2][0];
+ acceld->negate_z = ubootvar[2][1]<0?1:0;
+ /*kionix_accel_pdata.accel_direction = direction;
+ printk(KERN_ERR"accel_direction is %d,g_range is %d,res is %d\n",kionix_accel_pdata.accel_direction,kionix_accel_pdata.accel_g_range,kionix_accel_pdata.accel_res);*/
+
+ }
+ return 0;
+}
+
+static int kionix_i2c_read(struct i2c_client *client, u8 addr, u8 *data, int len)
+{
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 1,
+ .buf = &addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ return i2c_transfer(client->adapter, msgs, 2);
+}
+
+static int kionix_i2c_write(struct i2c_client *client, u8 addr, u8 *data, int len)
+{
+ char wrData[12] = {0};
+ /*
+ struct i2c_msg msgs =
+ {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,};
+*/
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = len+1,
+ .buf = wrData,
+ },
+ };
+
+ if (!client || (!data))
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ wrData[0] = addr;
+ strncpy(&wrData[1], data, len);
+
+ if (i2c_transfer(client->adapter, &msgs, 1) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int kionix_i2c_writebyte(struct i2c_client *client, u8 addr, u8 data)
+{
+ char wrData[2] = {0};
+ /*
+ struct i2c_msg msgs =
+ {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,};
+*/
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 2,
+ .buf = &wrData[0],
+ },
+ };
+
+ if (!client)
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ wrData[0] = addr;
+ //strncpy(&wrData[1], data, len);
+ wrData[1] = data;
+
+ if (i2c_transfer(client->adapter, &msgs, 1) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int kionix_strtok(const char *buf, size_t count, char **token, const int token_nr)
+{
+ char *buf2 = (char *)kzalloc((count + 1) * sizeof(char), GFP_KERNEL);
+ char **token2 = token;
+ unsigned int num_ptr = 0, num_nr = 0, num_neg = 0;
+ int i = 0, start = 0, end = (int)count;
+
+ strcpy(buf2, buf);
+
+ /* We need to breakup the string into separate chunks in order for kstrtoint
+ * or strict_strtol to parse them without returning an error. Stop when the end of
+ * the string is reached or when enough value is read from the string */
+ while((start < end) && (i < token_nr)) {
+ /* We found a negative sign */
+ if(*(buf2 + start) == '-') {
+ /* Previous char(s) are numeric, so we store their value first before proceed */
+ if(num_nr > 0) {
+ /* If there is a pending negative sign, we adjust the variables to account for it */
+ if(num_neg) {
+ num_ptr--;
+ num_nr++;
+ }
+ *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL);
+ strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr);
+ *(*token2+num_nr) = '\n';
+ i++;
+ token2++;
+ /* Reset */
+ num_ptr = num_nr = 0;
+ }
+ /* This indicates that there is a pending negative sign in the string */
+ num_neg = 1;
+ }
+ /* We found a numeric */
+ else if((*(buf2 + start) >= '0') && (*(buf2 + start) <= '9')) {
+ /* If the previous char(s) are not numeric, set num_ptr to current char */
+ if(num_nr < 1)
+ num_ptr = start;
+ num_nr++;
+ }
+ /* We found an unwanted character */
+ else {
+ /* Previous char(s) are numeric, so we store their value first before proceed */
+ if(num_nr > 0) {
+ if(num_neg) {
+ num_ptr--;
+ num_nr++;
+ }
+ *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL);
+ strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr);
+ *(*token2+num_nr) = '\n';
+ i++;
+ token2++;
+ }
+ /* Reset all the variables to start afresh */
+ num_ptr = num_nr = num_neg = 0;
+ }
+ start++;
+ }
+
+ kfree(buf2);
+
+ return (i == token_nr) ? token_nr : -1;
+}
+
+static int kionix_accel_grp1_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+ else {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp1_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \
+ acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp1_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp1_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ u8 accel_data[3];
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop = KIONIX_I2C_RETRY_COUNT;
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP1_XOUT, accel_data, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_x] >> 2)) - 32)) << 6;
+ y = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_y] >> 2)) - 32)) << 6;
+ z = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_z] >> 2)) - 32)) << 6;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+}
+
+static int kionix_accel_grp1_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp1_odr_table); i++) {
+ odr = kionix_accel_grp1_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp1_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update CTRL_REG1 register if the ODR is not changed */
+ if((acceld->accel_registers[accel_grp1_ctrl_reg1] & ACCEL_GRP1_ODR_MASK) == odr)
+ return 0;
+ else {
+ acceld->accel_registers[accel_grp1_ctrl_reg1] &= ~ACCEL_GRP1_ODR_MASK;
+ acceld->accel_registers[accel_grp1_ctrl_reg1] |= odr;
+ }
+
+ /* Do not need to update CTRL_REG1 register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \
+ acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp2_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ /* ensure that PC1 is cleared before updating control registers */
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ /* only write INT_CTRL_REG1 if in irq mode */
+ if (acceld->client->irq) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_INT_CTRL1, acceld->accel_registers[accel_grp2_int_ctrl]);
+ if (err < 0)
+ return err;
+ }
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+ else {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp2_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, \
+ acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp2_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(acceld->accel_drdy == 0)
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp2_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ struct { union {
+ s16 accel_data_s16[3];
+ s8 accel_data_s8[6];
+ }; } accel_data;
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop;
+
+ /* Only read the output registers if enabled */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP2_XOUT_L, (u8 *)accel_data.accel_data_s16, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift;
+ y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift;
+ z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+
+ /* Clear the interrupt if using drdy */
+ if(acceld->accel_drdy == 1) {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP2_INT_REL);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0)
+ KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err);
+ }
+}
+
+static void kionix_accel_grp2_update_g_range(struct kionix_accel_driver *acceld)
+{
+ acceld->accel_registers[accel_grp2_ctrl_reg1] &= ~ACCEL_GRP2_G_MASK;
+
+ switch (acceld->accel_pdata.accel_g_range) {
+ case KIONIX_ACCEL_G_8G:
+ case KIONIX_ACCEL_G_6G:
+ acceld->shift = 2;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_8G;
+ break;
+ case KIONIX_ACCEL_G_4G:
+ acceld->shift = 3;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_4G;
+ break;
+ case KIONIX_ACCEL_G_2G:
+ default:
+ acceld->shift = 4;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_2G;
+ break;
+ }
+
+ return;
+}
+
+static int kionix_accel_grp2_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp2_odr_table); i++) {
+ odr = kionix_accel_grp2_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp2_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */
+ if(acceld->accel_registers[accel_grp2_data_ctrl] == odr)
+ return 0;
+ else
+ acceld->accel_registers[accel_grp2_data_ctrl] = odr;
+
+ /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp4_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+ char rxData[2] = {0};
+ /* ensure that PC1 is cleared before updating control registers */
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, 0);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, 0);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d ,%s: ACCEL_GRP4_CTRL_REG1 is %d",__LINE__,__FUNCTION__,rxData[0]);*/
+
+ if (err < 0)
+ return err;
+
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],rxData[1]);*/
+
+ if (err < 0)
+ return err;
+
+ /* only write INT_CTRL_REG1 if in irq mode */
+ if (acceld->client->irq) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_INT_CTRL1, acceld->accel_registers[accel_grp4_int_ctrl]);
+ if (err < 0)
+ return err;
+ }
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",rxData[0],rxData[1]);*/
+
+ if (err < 0)
+ return err;
+ }
+ else {
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],acceld->accel_registers[accel_grp4_ctrl_reg1]);*/
+
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp4_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ /*err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, \
+ acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/
+
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, \
+ acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ if (err < 0)
+ return err;
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp4_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(acceld->accel_drdy == 0)
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp4_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ struct { union {
+ s16 accel_data_s16[3];
+ s8 accel_data_s8[6];
+ }; } accel_data;
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop;
+
+ /* Only read the output registers if enabled */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP4_XOUT_L, (u8 *)accel_data.accel_data_s16, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift;
+ y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift;
+ z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ //printk(KERN_ERR"x:%d,y:%d,z:%d",x,y,z);
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+
+ /* Clear the interrupt if using drdy */
+ if(acceld->accel_drdy == 1) {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_INT_REL);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0)
+ KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err);
+ }
+}
+
+static void kionix_accel_grp4_update_g_range(struct kionix_accel_driver *acceld)
+{
+ acceld->accel_registers[accel_grp4_ctrl_reg1] &= ~ACCEL_GRP4_G_MASK;
+ //printk(KERN_ERR"kionix_accel_grp4_update_g_range is %d",acceld->accel_pdata.accel_g_range);
+ switch (acceld->accel_pdata.accel_g_range) {
+ case KIONIX_ACCEL_G_8G:
+ case KIONIX_ACCEL_G_6G:
+ //acceld->shift = 2;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_8G;
+ break;
+ case KIONIX_ACCEL_G_4G:
+ //acceld->shift = 4;//3;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_4G;
+ break;
+ case KIONIX_ACCEL_G_2G:
+ default:
+ //acceld->shift = 4;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_2G;
+ break;
+ }
+
+ return;
+}
+
+static int kionix_accel_grp4_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp4_odr_table); i++) {
+ odr = kionix_accel_grp4_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp4_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */
+ if(acceld->accel_registers[accel_grp4_data_ctrl] == odr)
+ return 0;
+ else
+ acceld->accel_registers[accel_grp4_data_ctrl] = odr;
+
+ /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+
+
+ if (err < 0)
+ return err;
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ if (err < 0)
+ return err;
+ //#############
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL);
+ if (err < 0)
+ return err;
+ switch(err) {
+ case ACCEL_GRP4_ODR0_781:
+ dev_info(&acceld->client->dev, "ODR = 0.781 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR1_563:
+ dev_info(&acceld->client->dev, "ODR = 1.563 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR3_125:
+ dev_info(&acceld->client->dev, "ODR = 3.125 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR6_25:
+ dev_info(&acceld->client->dev, "ODR = 6.25 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR12_5:
+ dev_info(&acceld->client->dev, "ODR = 12.5 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR25:
+ dev_info(&acceld->client->dev, "ODR = 25 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR50:
+ dev_info(&acceld->client->dev, "ODR = 50 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR100:
+ dev_info(&acceld->client->dev, "ODR = 100 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR200:
+ dev_info(&acceld->client->dev, "ODR = 200 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR400:
+ dev_info(&acceld->client->dev, "ODR = 400 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR800:
+ dev_info(&acceld->client->dev, "ODR = 800 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR1600:
+ dev_info(&acceld->client->dev, "ODR = 1600 Hz\n");
+ break;
+ default:
+ dev_info(&acceld->client->dev, "Unknown ODR\n");
+ break;
+ }
+ //#############
+ }
+
+ return 0;
+}
+
+static int kionix_accel_power_on(struct kionix_accel_driver *acceld)
+{
+ if (acceld->accel_pdata.power_on)
+ return acceld->accel_pdata.power_on();
+
+ return 0;
+}
+
+static void kionix_accel_power_off(struct kionix_accel_driver *acceld)
+{
+ if (acceld->accel_pdata.power_off)
+ acceld->accel_pdata.power_off();
+}
+
+static irqreturn_t kionix_accel_isr(int irq, void *dev)
+{
+ struct kionix_accel_driver *acceld = dev;
+
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static void kionix_accel_work(struct work_struct *work)
+{
+ struct kionix_accel_driver *acceld = container_of((struct delayed_work *)work, struct kionix_accel_driver, accel_work);
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+
+ acceld->kionix_accel_report_accel_data(acceld);
+}
+
+static void kionix_accel_update_direction(struct kionix_accel_driver *acceld)
+{
+ unsigned int direction = acceld->accel_pdata.accel_direction;
+ unsigned int accel_group = acceld->accel_group;
+
+ write_lock(&acceld->rwlock_accel_data);
+ acceld->axis_map_x = ((direction-1)%2);
+ acceld->axis_map_y = (direction%2);
+ acceld->axis_map_z = 2;
+ acceld->negate_z = ((direction-1)/4);
+ switch(accel_group) {
+ case KIONIX_ACCEL_GRP3:
+ case KIONIX_ACCEL_GRP6:
+ acceld->negate_x = (((direction+2)/2)%2);
+ acceld->negate_y = (((direction+5)/4)%2);
+ break;
+ case KIONIX_ACCEL_GRP5:
+ acceld->axis_map_x = (direction%2);
+ acceld->axis_map_y = ((direction-1)%2);
+ acceld->negate_x = (((direction+1)/2)%2);
+ acceld->negate_y = (((direction/2)+((direction-1)/4))%2);
+ break;
+ default:
+ acceld->negate_x = ((direction/2)%2);
+ acceld->negate_y = (((direction+1)/4)%2);
+ break;
+ }
+ write_unlock(&acceld->rwlock_accel_data);
+ return;
+}
+
+static int kionix_accel_enable(struct kionix_accel_driver *acceld)
+{
+ int err = 0;
+ long remaining;
+
+ mutex_lock(&acceld->mutex_earlysuspend);
+
+ atomic_set(&acceld->accel_suspend_continue, 0);
+
+ /* Make sure that the sensor had successfully resumed before enabling it */
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ KMSGINF(&acceld->client->dev, "%s: waiting for resume\n", __func__);
+ remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \
+ atomic_read(&acceld->accel_suspended) == 0, \
+ msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT));
+
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ KMSGERR(&acceld->client->dev, "%s: timeout waiting for resume\n", __func__);
+ err = -ETIME;
+ goto exit;
+ }
+ }
+
+ err = acceld->kionix_accel_operate(acceld);
+
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kionix_accel_operate returned err = %d\n", __func__, err);
+ goto exit;
+ }
+
+ atomic_inc(&acceld->accel_enabled);
+
+exit:
+ mutex_unlock(&acceld->mutex_earlysuspend);
+
+ return err;
+}
+
+static int kionix_accel_disable(struct kionix_accel_driver *acceld)
+{
+ int err = 0;
+
+ mutex_lock(&acceld->mutex_resume);
+
+ atomic_set(&acceld->accel_suspend_continue, 1);
+
+ if(atomic_read(&acceld->accel_enabled) > 0){
+ if(atomic_dec_and_test(&acceld->accel_enabled)) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ atomic_set(&acceld->accel_enable_resume, 0);
+ err = acceld->kionix_accel_standby(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kionix_accel_standby returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ wake_up_interruptible(&acceld->wqh_suspend);
+ }
+ }
+
+exit:
+ mutex_unlock(&acceld->mutex_resume);
+
+ return err;
+}
+
+static int kionix_accel_input_open(struct input_dev *input)
+{
+ struct kionix_accel_driver *acceld = input_get_drvdata(input);
+
+ atomic_inc(&acceld->accel_input_event);
+
+ return 0;
+}
+
+static void kionix_accel_input_close(struct input_dev *dev)
+{
+ struct kionix_accel_driver *acceld = input_get_drvdata(dev);
+
+ atomic_dec(&acceld->accel_input_event);
+}
+
+static void __devinit kionix_accel_init_input_device(struct kionix_accel_driver *acceld,
+ struct input_dev *input_dev)
+{
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_X, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+ input_set_abs_params(input_dev, ABS_Y, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+ input_set_abs_params(input_dev, ABS_Z, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+
+ input_dev->name = "g-sensor";//KIONIX_ACCEL_NAME;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &acceld->client->dev;
+}
+
+static int __devinit kionix_accel_setup_input_device(struct kionix_accel_driver *acceld)
+{
+ struct input_dev *input_dev;
+ int err;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ KMSGERR(&acceld->client->dev, "input_allocate_device failed\n");
+ printk("kionix_accel_probe: Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ acceld->input_dev = input_dev;
+
+ input_dev->open = kionix_accel_input_open;
+ input_dev->close = kionix_accel_input_close;
+ input_set_drvdata(input_dev, acceld);
+
+ kionix_accel_init_input_device(acceld, input_dev);
+
+ err = input_register_device(acceld->input_dev);
+ if (err) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: input_register_device returned err = %d\n", __func__, err);
+ printk("kionix_accel_probe: Failed to register input device\n");
+ input_free_device(acceld->input_dev);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Returns the enable state of device */
+static ssize_t kionix_accel_get_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", atomic_read(&acceld->accel_enabled) > 0 ? 1 : 0);
+}
+
+/* Allow users to enable/disable the device */
+static ssize_t kionix_accel_set_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int enable_count = 1;
+ unsigned long enable;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, enable_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No enable data being read. " \
+ "No enable data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&enable);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &enable);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(enable)
+ err = kionix_accel_enable(acceld);
+ else
+ err = kionix_accel_disable(acceld);
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ return (err < 0) ? err : count;
+}
+
+/* Returns currently selected poll interval (in ms) */
+static ssize_t kionix_accel_get_delay(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", acceld->poll_interval);
+}
+
+/* Allow users to select a new poll interval (in ms) */
+static ssize_t kionix_accel_set_delay(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int delay_count = 1;
+ unsigned long interval;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, delay_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No delay data being read. " \
+ "No delay data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&interval);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &interval);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(acceld->accel_drdy == 1)
+ disable_irq(client->irq);
+
+ /*
+ * Set current interval to the greater of the minimum interval or
+ * the requested interval
+ */
+ acceld->poll_interval = max((unsigned int)interval, acceld->accel_pdata.min_interval);
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+
+ err = acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+
+ if(acceld->accel_drdy == 1)
+ enable_irq(client->irq);
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+
+ return (err < 0) ? err : count;
+}
+
+/* Returns the direction of device */
+static ssize_t kionix_accel_get_direct(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", acceld->accel_pdata.accel_direction);
+}
+
+/* Allow users to change the direction the device */
+static ssize_t kionix_accel_set_direct(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int direct_count = 1;
+ unsigned long direction;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, direct_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No direction data being read. " \
+ "No direction data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&direction);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &direction);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(direction < 1 || direction > 8)
+ KMSGERR(&acceld->client->dev, "%s: invalid direction = %d\n", __func__, (unsigned int) direction);
+
+ else {
+ acceld->accel_pdata.accel_direction = (u8) direction;
+ kionix_accel_update_direction(acceld);
+ }
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ return (err < 0) ? err : count;
+}
+
+/* Returns the data output of device */
+static ssize_t kionix_accel_get_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ int x, y, z;
+
+ read_lock(&acceld->rwlock_accel_data);
+
+ x = acceld->accel_data[acceld->axis_map_x];
+ y = acceld->accel_data[acceld->axis_map_y];
+ z = acceld->accel_data[acceld->axis_map_z];
+
+ read_unlock(&acceld->rwlock_accel_data);
+
+ return sprintf(buf, "%d %d %d\n", x, y, z);
+}
+
+/* Returns the calibration value of the device */
+static ssize_t kionix_accel_get_cali(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ int calibration[3];
+
+ read_lock(&acceld->rwlock_accel_data);
+
+ calibration[0] = acceld->accel_cali[acceld->axis_map_x];
+ calibration[1] = acceld->accel_cali[acceld->axis_map_y];
+ calibration[2] = acceld->accel_cali[acceld->axis_map_z];
+
+ read_unlock(&acceld->rwlock_accel_data);
+
+ return sprintf(buf, "%d %d %d\n", calibration[0], calibration[1], calibration[2]);
+}
+
+/* Allow users to change the calibration value of the device */
+static ssize_t kionix_accel_set_cali(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ const int cali_count = 3; /* How many calibration that we expect to get from the string */
+ char **buf2;
+ long calibration[cali_count];
+ int err = 0, i = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ buf2 = (char **)kzalloc(cali_count * sizeof(char *), GFP_KERNEL);
+
+ if(kionix_strtok(buf, count, buf2, cali_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: Not enough calibration data being read. " \
+ "No calibration data will be updated.\n", __func__);
+ }
+ else {
+ /* Convert string to integers */
+ for(i = 0 ; i < cali_count ; i++) {
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtoint((const char *)*(buf2+i), 10, (int *)&calibration[i]);
+ if(err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtoint returned err = %d." \
+ "No calibration data will be updated.\n", __func__ , err);
+ goto exit;
+ }
+ #else
+ err = strict_strtol((const char *)*(buf2+i), 10, &calibration[i]);
+ if(err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtol returned err = %d." \
+ "No calibration data will be updated.\n", __func__ , err);
+ goto exit;
+ }
+ #endif
+ }
+
+ write_lock(&acceld->rwlock_accel_data);
+
+ acceld->accel_cali[acceld->axis_map_x] = (int)calibration[0];
+ acceld->accel_cali[acceld->axis_map_y] = (int)calibration[1];
+ acceld->accel_cali[acceld->axis_map_z] = (int)calibration[2];
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+
+exit:
+ for(i = 0 ; i < cali_count ; i++)
+ kfree(*(buf2+i));
+
+ kfree(buf2);
+
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+
+ return (err < 0) ? err : count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kionix_accel_get_enable, kionix_accel_set_enable);
+static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kionix_accel_get_delay, kionix_accel_set_delay);
+static DEVICE_ATTR(direct, S_IRUGO|S_IWUSR, kionix_accel_get_direct, kionix_accel_set_direct);
+static DEVICE_ATTR(data, S_IRUGO, kionix_accel_get_data, NULL);
+static DEVICE_ATTR(cali, S_IRUGO|S_IWUSR, kionix_accel_get_cali, kionix_accel_set_cali);
+
+static struct attribute *kionix_accel_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_direct.attr,
+ &dev_attr_data.attr,
+ &dev_attr_cali.attr,
+ NULL
+};
+
+static struct attribute_group kionix_accel_attribute_group = {
+ .attrs = kionix_accel_attributes
+};
+
+static int kionix_chip_id[] ={
+ KIONIX_ACCEL_WHO_AM_I_KXTE9,
+ KIONIX_ACCEL_WHO_AM_I_KXTF9,
+ KIONIX_ACCEL_WHO_AM_I_KXTI9_1001,
+ KIONIX_ACCEL_WHO_AM_I_KXTIK_1004,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007,
+ KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009,
+ KIONIX_ACCEL_WHO_AM_I_KXCJK_1013
+};
+
+static int iskionix()
+{
+ char rxData[2] = {0};
+ int ret = 0;
+ int i = 0;
+
+ ret = kionix_i2c_read(this_client,ACCEL_WHO_AM_I,rxData,1); //maybe should 2 success // -5 ioerror!!
+ printk(KERN_ERR"<<<<%s ret:%d val 0x%x\n", __FUNCTION__, ret, rxData[0]);
+ if (ret <= 0) // 2 ?
+ {
+ return -1;
+ }
+ for(i = 0 ; i < sizeof(kionix_chip_id)/sizeof(kionix_chip_id[0]);i++)
+ if(rxData[0] == kionix_chip_id[i])
+ return 0;
+
+ return -1;
+}
+
+static int __devinit kionix_verify(struct kionix_accel_driver *acceld)
+{
+ int retval = i2c_smbus_read_byte_data(acceld->client, ACCEL_WHO_AM_I);
+
+#if KIONIX_KMSG_INF
+ switch (retval) {
+ case KIONIX_ACCEL_WHO_AM_I_KXTE9:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTE9.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTF9:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTF9.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTI9-1001.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTIK-1004.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1005.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1007.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJ9-1008.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ2-1009.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJK-1013.\n");
+ break;
+ default:
+ break;
+ }
+#endif
+
+ return retval;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void kionix_accel_earlysuspend_suspend(struct early_suspend *h)
+{
+ struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend);
+ long remaining;
+
+ mutex_lock(&acceld->mutex_earlysuspend);
+
+ /* Only continue to suspend if enable did not intervene */
+ if(atomic_read(&acceld->accel_suspend_continue) > 0) {
+ /* Make sure that the sensor had successfully disabled before suspending it */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ KMSGINF(&acceld->client->dev, "%s: waiting for disable\n", __func__);
+ remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \
+ atomic_read(&acceld->accel_enabled) < 1, \
+ msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT));
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ KMSGERR(&acceld->client->dev, "%s: timeout waiting for disable\n", __func__);
+ }
+ }
+
+ kionix_accel_power_off(acceld);
+
+ atomic_set(&acceld->accel_suspended, 1);
+ }
+
+ mutex_unlock(&acceld->mutex_earlysuspend);
+
+ return;
+}
+
+void kionix_accel_earlysuspend_resume(struct early_suspend *h)
+{
+ struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend);
+ int err;
+
+ mutex_lock(&acceld->mutex_resume);
+
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ err = kionix_accel_power_on(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on returned err = %d\n", __func__, err);
+ goto exit;
+ }
+
+ /* Only needs to reinitialized the registers if Vdd is pulled low during suspend */
+ if(err > 0) {
+ err = acceld->kionix_accel_power_on_init(acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ }
+
+ atomic_set(&acceld->accel_suspended, 0);
+ }
+
+ wake_up_interruptible(&acceld->wqh_suspend);
+
+exit:
+ mutex_unlock(&acceld->mutex_resume);
+
+ return;
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+static int kionix_open(struct inode *inode, struct file *file)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+ //KMSGINF("Open the g-sensor node...\n");
+ kionix_accel_input_open(acceld->input_dev);
+ return 0;
+}
+
+static int kionix_release(struct inode *inode, struct file *file)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+ //KMSGINF("Close the g-sensor node...\n");
+ kionix_accel_input_close(acceld->input_dev);
+ return 0;
+}
+
+static long
+kionix_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ char rwbuf[5];
+ short delay, enable; //amsr = -1;
+ unsigned int uval = 0;
+
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+
+ //KMSGINF("g-sensor ioctr...\n");
+ memset(rwbuf, 0, sizeof(rwbuf));
+ switch (cmd) {
+ case ECS_IOCTL_APP_SET_DELAY:
+ // set the rate of g-sensor
+ if (copy_from_user(&delay, argp, sizeof(short)))
+ {
+ printk(KERN_ALERT "Can't get set delay!!!\n");
+ return -EFAULT;
+ }
+ klog("Get delay=%d\n", delay);
+
+ if ((delay >=0) && (delay < 20))
+ {
+ delay = 20;
+ } else if (delay > 200)
+ {
+ delay = 200;
+ }
+ //l_sensorconfig.sensor_samp = 1000/delay;
+ acceld->poll_interval = 1000/delay;
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+ acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ // enable/disable sensor
+ if (copy_from_user(&enable, argp, sizeof(short)))
+ {
+ printk(KERN_ERR "Can't get enable flag!!!\n");
+ return -EFAULT;
+ }
+ klog("enable=%d\n",enable);
+ if ((enable >=0) && (enable <=1))
+ {
+ //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable);
+
+ //l_sensorconfig.sensor_enable = enable;
+ if(enable)
+ kionix_accel_enable(acceld);
+ else
+ kionix_accel_disable(acceld);
+
+ } else {
+ printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = KIONIX_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ //KMSGINF("kionix_driver_id:%d\n",uval);
+ break;
+ case WMT_IOCTL_SENOR_GET_RESOLUTION:
+
+ uval = (12<<8) | 8; // 8bit:4g 0xxx xx //mma8452Q
+ if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ printk("<<<<<<<resolution:0x%x\n",uval);
+ default:
+ break;
+ }
+
+
+
+ return 0;
+}
+
+static struct file_operations kionix_fops = {
+ .owner = THIS_MODULE,
+ .open = kionix_open,
+ .release = kionix_release,
+ .unlocked_ioctl = kionix_ioctl,
+};
+
+
+static struct miscdevice kionix_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sensor_ctrl",
+ .fops = &kionix_fops,
+};
+
+static int sensor_writeproc( struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data )
+{
+ return 0;
+}
+
+static int sensor_readproc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+
+
+
+/*static int __devinit kionix_accel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)*/
+static int kionix_accel_probe(struct platform_device *pdev)
+{
+ const struct kionix_accel_platform_data *accel_pdata = this_client->dev.platform_data;
+ struct kionix_accel_driver *acceld;
+ int err;
+ struct proc_dir_entry *proc_dir, *proc_entry;
+/*
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
+ KMSGERR(&client->dev, "client is not i2c capable. Abort.\n");
+ return -ENXIO;
+ }
+*/
+ if (!accel_pdata) {
+ KMSGERR(&this_client->dev, "platform data is NULL. Abort.\n");
+ return -EINVAL;
+ }
+
+ acceld = kzalloc(sizeof(*acceld), GFP_KERNEL);
+ if (acceld == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for module data. Abort.\n");
+ return -ENOMEM;
+ }
+
+ acceld->client = this_client;
+ acceld->accel_pdata = *accel_pdata;
+
+ i2c_set_clientdata(this_client, acceld);
+
+ err = kionix_accel_power_on(acceld);
+ if (err < 0)
+ goto err_free_mem;
+
+ if (accel_pdata->init) {
+ err = accel_pdata->init();
+ if (err < 0)
+ goto err_accel_pdata_power_off;
+ }
+
+ err = kionix_verify(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_verify returned err = %d. Abort.\n", __func__, err);
+ goto err_accel_pdata_exit;
+ }
+
+ /* Setup group specific configuration and function callback */
+ switch (err) {
+ case KIONIX_ACCEL_WHO_AM_I_KXTE9:
+ acceld->accel_group = KIONIX_ACCEL_GRP1;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp1_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ acceld->accel_drdy = 0;
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp1_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp1_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp1_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp1_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp1_standby;
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTF9:
+ case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001:
+ case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004:
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005:
+ if(err == KIONIX_ACCEL_WHO_AM_I_KXTIK_1004)
+ acceld->accel_group = KIONIX_ACCEL_GRP3;
+ else
+ acceld->accel_group = KIONIX_ACCEL_GRP2;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp2_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ switch(acceld->accel_pdata.accel_res) {
+ case KIONIX_ACCEL_RES_6BIT:
+ case KIONIX_ACCEL_RES_8BIT:
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_8BIT;
+ break;
+ case KIONIX_ACCEL_RES_12BIT:
+ default:
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_12BIT;
+ break;
+ }
+ if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) {
+ acceld->accel_registers[accel_grp2_int_ctrl] |= ACCEL_GRP2_IEN | ACCEL_GRP2_IEA;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_DRDYE;
+ acceld->accel_drdy = 1;
+ }
+ else
+ acceld->accel_drdy = 0;
+ kionix_accel_grp2_update_g_range(acceld);
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp2_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp2_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp2_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp2_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp2_standby;
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007:
+ case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008:
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009:
+ case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013:
+ if(err == KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009)
+ acceld->accel_group = KIONIX_ACCEL_GRP5;
+ else if(err == KIONIX_ACCEL_WHO_AM_I_KXCJK_1013)
+ acceld->accel_group = KIONIX_ACCEL_GRP6;
+ else
+ acceld->accel_group = KIONIX_ACCEL_GRP4;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp4_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ switch(acceld->accel_pdata.accel_res) {
+ case KIONIX_ACCEL_RES_6BIT:
+ case KIONIX_ACCEL_RES_8BIT:
+ acceld->shift = 0;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_8BIT;
+ break;
+ case KIONIX_ACCEL_RES_12BIT:
+ acceld->shift = 4;
+ default:
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_12BIT;
+ break;
+ }
+ if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) {
+ acceld->accel_registers[accel_grp4_int_ctrl] |= ACCEL_GRP4_IEN | ACCEL_GRP4_IEA;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_DRDYE;
+ acceld->accel_drdy = 1;
+ }
+ else
+ acceld->accel_drdy = 0;
+ kionix_accel_grp4_update_g_range(acceld);
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp4_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp4_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp4_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp4_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp4_standby;
+ break;
+ default:
+ KMSGERR(&acceld->client->dev, \
+ "%s: unsupported device, who am i = %d. Abort.\n", __func__, err);
+ goto err_accel_pdata_exit;
+ }
+
+ err = kionix_accel_setup_input_device(acceld);
+ if (err)
+ goto err_free_accel_registers;
+
+//add
+ /*this_pdev = pdev;
+ l_sensorconfig.input_dev = acceld->input_dev;*/
+
+ err = misc_register(&kionix_device);
+ if (err) {
+ printk(KERN_ERR
+ "kionix_accel_probe: kionix_device register failed\n");
+ goto exit_misc_device_register_failed;
+ }
+
+ //dev_set_drvdata(&pdev->dev, &l_sensorconfig);
+//end add
+
+
+ atomic_set(&acceld->accel_suspended, 0);
+ atomic_set(&acceld->accel_suspend_continue, 1);
+ atomic_set(&acceld->accel_enabled, 0);
+ atomic_set(&acceld->accel_input_event, 0);
+ atomic_set(&acceld->accel_enable_resume, 0);
+
+ mutex_init(&acceld->mutex_earlysuspend);
+ mutex_init(&acceld->mutex_resume);
+
+ mutex_init(&acceld->mutex_subinput);//add 2014-6-12
+
+ rwlock_init(&acceld->rwlock_accel_data);
+
+ acceld->poll_interval = acceld->accel_pdata.poll_interval;
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+ acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+ get_axisset(acceld);//kionix_accel_update_direction(acceld);
+
+ proc_dir = proc_mkdir("sensors", NULL);
+ if (proc_dir == NULL)
+ KMSGERR(&this_client->dev, "failed to create /proc/sensors\n");
+ else {
+ proc_entry = create_proc_entry( "accelinfo", 0644, proc_dir);
+ if (proc_entry == NULL)
+ KMSGERR(&this_client->dev, "failed to create /proc/cpu/accelinfo\n");
+ }
+
+/*
+ proc_dir = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL);//&proc_root
+ if (proc_dir != NULL)
+ {
+ proc_dir->write_proc = sensor_writeproc;
+ proc_dir->read_proc = sensor_readproc;
+ }
+*/
+ acceld->accel_workqueue = create_singlethread_workqueue("Kionix Accel Workqueue");
+ INIT_DELAYED_WORK(&acceld->accel_work, kionix_accel_work);
+ init_waitqueue_head(&acceld->wqh_suspend);
+
+ if (acceld->accel_drdy) {
+ err = request_threaded_irq(this_client->irq, NULL, kionix_accel_isr, \
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, \
+ KIONIX_ACCEL_IRQ, acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: request_threaded_irq returned err = %d\n", __func__, err);
+ KMSGERR(&acceld->client->dev, "%s: running in software polling mode instead\n", __func__);
+ acceld->accel_drdy = 0;
+ }
+ KMSGINF(&acceld->client->dev, "running in hardware interrupt mode\n");
+ } else {
+ KMSGINF(&acceld->client->dev, "running in software polling mode\n");
+ }
+
+ err = acceld->kionix_accel_power_on_init(acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d. Abort.\n", __func__, err);
+ goto err_free_irq;
+ }
+
+ err = sysfs_create_group(&this_client->dev.kobj, &kionix_accel_attribute_group);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: sysfs_create_group returned err = %d. Abort.\n", __func__, err);
+ goto err_free_irq;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ /* The higher the level, the earlier it resume, and the later it suspend */
+ acceld->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50;
+ acceld->early_suspend.suspend = kionix_accel_earlysuspend_suspend;
+ acceld->early_suspend.resume = kionix_accel_earlysuspend_resume;
+ register_early_suspend(&acceld->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+
+ // satrt the polling work
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+ return 0;
+
+exit_misc_device_register_failed:
+err_free_irq:
+ if (acceld->accel_drdy)
+ free_irq(this_client->irq, acceld);
+ destroy_workqueue(acceld->accel_workqueue);
+ input_unregister_device(acceld->input_dev);
+err_free_accel_registers:
+ kfree(acceld->accel_registers);
+err_accel_pdata_exit:
+ if (accel_pdata->exit)
+ accel_pdata->exit();
+err_accel_pdata_power_off:
+ kionix_accel_power_off(acceld);
+err_free_mem:
+ kfree(acceld);
+exit_input_dev_alloc_failed:
+ return err;
+}
+
+static int kionix_accel_remove(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&acceld->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+ if (NULL != acceld->accel_workqueue)
+ {
+ cancel_delayed_work_sync(&acceld->accel_work);
+ flush_workqueue(acceld->accel_workqueue);
+ destroy_workqueue(acceld->accel_workqueue);
+ acceld->accel_workqueue = NULL;
+ }
+ sysfs_remove_group(&this_client->dev.kobj, &kionix_accel_attribute_group);
+ if (acceld->accel_drdy)
+ free_irq(this_client->irq, acceld);
+ //destroy_workqueue(acceld->accel_workqueue);
+ misc_deregister(&kionix_device);
+ input_unregister_device(acceld->input_dev);
+ kfree(acceld->accel_registers);
+ if (acceld->accel_pdata.exit)
+ acceld->accel_pdata.exit();
+ kionix_accel_power_off(acceld);
+ kfree(acceld);
+
+ return 0;
+}
+
+static int __devexit kionix_accel_i2cremove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id kionix_accel_id[] = {
+ { KIONIX_ACCEL_NAME, 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, kionix_accel_id);
+
+static struct i2c_driver kionix_accel_driver = {
+ .driver = {
+ .name = KIONIX_ACCEL_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = kionix_accel_probe,
+ .remove = __devexit_p(kionix_accel_i2cremove),
+ .id_table = kionix_accel_id,
+};
+
+
+static struct platform_device kionix_pdevice = {
+ .name = "kionix",
+ .id = 0,
+ /*.dev = {
+ //.release = mma8452q_platform_release,
+ },*/
+};
+
+//************
+static void kionix_accel_shutdown(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ flush_delayed_work_sync(&acceld->accel_work);
+ cancel_delayed_work_sync(&acceld->accel_work);
+ }
+
+}
+//****add for resume dpm timeout 2014-6-12
+static int kionix_accel_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ flush_delayed_work_sync(&acceld->accel_work);
+ cancel_delayed_work_sync(&acceld->accel_work);
+ }
+}
+
+int kionix_accel_resume(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+ }
+}
+//***********************
+static struct platform_driver kionix_driver = {
+ .probe = kionix_accel_probe,
+ .remove = kionix_accel_remove,
+ .shutdown = kionix_accel_shutdown,
+ .suspend = kionix_accel_suspend,
+ .resume = kionix_accel_resume,
+ .driver = {
+ .name = "kionix",
+ },
+};
+
+
+static struct class* l_dev_class = NULL;
+static struct device *l_clsdevice = NULL;
+static int __init kionix_accel_init(void)
+{
+ //return i2c_add_driver(&kionix_accel_driver);
+
+ int ret = 0;
+ struct kionix_accel_driver *acceld;
+
+ acceld = kzalloc(sizeof(*acceld), GFP_KERNEL);
+ if (acceld == NULL) {
+ printk("%s kzalloc fail!\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = get_axisset(acceld);//
+ if (ret < 0)
+ {
+ printk("%s user choose to no sensor chip!\n", __func__);
+ kfree(acceld);
+ return ret;
+ }
+ kfree(acceld);
+
+ if (!(this_client = sensor_i2c_register_device2(0, KIONIX_ACCEL_I2C_ADDR, KIONIX_ACCEL_NAME,(void*)(&kionix_accel_pdata))))
+ {
+ printk(KERN_EMERG"Can't register gsensor i2c device!\n");
+ return -1;
+ }
+
+
+ if(iskionix())
+ {
+ printk(KERN_ERR "Can't find kionix!!\n");
+ sensor_i2c_unregister_device(this_client);
+ return -1;
+ }
+
+ //ret = get_axisset(NULL);
+
+ printk("kionix g-sensor driver init\n");
+
+ //spin_lock_init(&l_sensorconfig.spinlock);
+ l_dev_class = class_create(THIS_MODULE, KIONIX_ACCEL_NAME);
+ //for S40 module to judge whether insmod is ok
+ if (IS_ERR(l_dev_class)){
+ ret = PTR_ERR(l_dev_class);
+ printk(KERN_ERR "Can't class_create gsensor device !!\n");
+ return ret;
+ }
+ l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, KIONIX_ACCEL_NAME);
+ if (IS_ERR(l_clsdevice)){
+ ret = PTR_ERR(l_clsdevice);
+ printk(KERN_ERR "Failed to create device %s !!!",KIONIX_ACCEL_NAME);
+ return ret;
+ }
+
+ if((ret = platform_device_register(&kionix_pdevice)))
+ {
+ printk(KERN_ERR "%s Can't register kionix platform devcie!!!\n", __FUNCTION__);
+ return ret;
+ }
+ if ((ret = platform_driver_register(&kionix_driver)) != 0)
+ {
+ printk(KERN_ERR "%s Can't register kionix platform driver!!!\n", __FUNCTION__);
+ return ret;
+ }
+
+ return 0;
+
+}
+module_init(kionix_accel_init);
+
+static void __exit kionix_accel_exit(void)
+{
+ //i2c_del_driver(&kionix_accel_driver);
+ platform_driver_unregister(&kionix_driver);
+ platform_device_unregister(&kionix_pdevice);
+
+ device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0));
+
+ class_destroy(l_dev_class);
+ sensor_i2c_unregister_device(this_client);
+}
+module_exit(kionix_accel_exit);
+
+MODULE_DESCRIPTION("Kionix accelerometer driver");
+MODULE_AUTHOR("Kuching Tan <kuchingtan@kionix.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("3.3.0");