MLK-10835-1 misc: fxas2100x: add Freescale FXAS2100X gyroscope sensor
authorFugang Duan <b38611@freescale.com>
Tue, 5 May 2015 09:08:34 +0000 (17:08 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:46:50 +0000 (14:46 -0500)
Add Freescale FXAS2100X gyroscope sensor

Signed-off-by: Fugang Duan <B38611@freescale.com>
(cherry picked from commit: 34a99f00d4886f95a8cf8cd4acbf37a82c67e46c)

drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/fxas2100x.c [new file with mode: 0644]

index 64971ba..fcd4d7c 100644 (file)
@@ -335,6 +335,16 @@ config ISL29020
          This driver can also be built as a module.  If so, the module
          will be called isl29020.
 
+config SENSORS_FXAS2100X
+       tristate "Freescale FXAS2100X gyroscope sensor"
+       depends on I2C && SYSFS
+       help
+         If you say yes here you get support for the Freescale FXAS2100X
+         gyroscope sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called fxas2100x.
+
 config SENSORS_TSL2550
        tristate "Taos TSL2550 ambient light sensor"
        depends on I2C && SYSFS
index 3198336..88cc6af 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
 obj-$(CONFIG_PHANTOM)          += phantom.o
 obj-$(CONFIG_QCOM_COINCELL)    += qcom-coincell.o
+obj-$(CONFIG_SENSORS_FXAS2100X) += fxas2100x.o
 obj-$(CONFIG_SENSORS_BH1770)   += bh1770glc.o
 obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
diff --git a/drivers/misc/fxas2100x.c b/drivers/misc/fxas2100x.c
new file mode 100644 (file)
index 0000000..3ac7180
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. 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 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+
+#define        SENSOR_IOCTL_BASE       'S'
+#define        SENSOR_GET_MODEL_NAME           _IOR(SENSOR_IOCTL_BASE, 0, char *)
+#define        SENSOR_GET_POWER_STATUS         _IOR(SENSOR_IOCTL_BASE, 2, int)
+#define        SENSOR_SET_POWER_STATUS         _IOR(SENSOR_IOCTL_BASE, 3, int)
+#define        SENSOR_GET_DELAY_TIME           _IOR(SENSOR_IOCTL_BASE, 4, int)
+#define        SENSOR_SET_DELAY_TIME           _IOR(SENSOR_IOCTL_BASE, 5, int)
+#define        SENSOR_GET_RAW_DATA             _IOR(SENSOR_IOCTL_BASE, 6, short[3])
+
+#define FXAS2100X_I2C_ADDR     0x20
+#define FXAS21000_CHIP_ID      0xD1
+#define FXAS21002_CHID_ID_1    0xD6
+#define FXAS21002_CHID_ID_2    0xD7
+
+#define FXAS2100X_POSITION_DEFAULT     2
+#define FXAS2100X_DELAY_DEFAULT                200
+
+#define FXAS2100X_STATUS_ZYXDR 0x08
+#define FXAS2100X_BUF_SIZE     6
+
+#define FXAS2100X_POLL_INTERVAL        400
+#define FXAS2100X_POLL_MAX     800
+#define FXAS2100X_POLL_MIN     200
+#define ABSMIN_GYRO_VAL                -32768
+#define ABSMAX_GYRO_VAL                32768
+
+#define FXAS2100X_DRIVER       "fxas2100x"
+
+/* register enum for fxas2100x registers */
+enum {
+       FXAS2100X_STATUS = 0x00,
+       FXAS2100X_OUT_X_MSB,
+       FXAS2100X_OUT_X_LSB,
+       FXAS2100X_OUT_Y_MSB,
+       FXAS2100X_OUT_Y_LSB,
+       FXAS2100X_OUT_Z_MSB,
+       FXAS2100X_OUT_Z_LSB,
+       FXAS2100X_DR_STATUS,
+       FXAS2100X_F_STATUS,
+       FXAS2100X_F_SETUP,
+       FXAS2100X_F_EVENT,
+       FXAS2100X_INT_SRC_FLAG,
+       FXAS2100X_WHO_AM_I,
+       FXAS2100X_CTRL_REG0,
+       FXAS2100X_RT_CFG,
+       FXAS2100X_RT_SRC,
+       FXAS2100X_RT_THS,
+       FXAS2100X_RT_COUNT,
+       FXAS2100X_TEMP,
+       FXAS2100X_CTRL_REG1,
+       FXAS2100X_CTRL_REG2,
+       FXAS2100X_CTRL_REG3, /* fxos21002 special */
+       FXAS2100X_REG_END,
+};
+
+enum {
+       STANDBY = 0,
+       ACTIVED,
+};
+
+struct fxas2100x_data_axis {
+       short x;
+       short y;
+       short z;
+};
+
+struct fxas2100x_data {
+       struct i2c_client *client;
+       struct input_polled_dev *input_polled;
+       atomic_t active;
+       atomic_t active_poll;
+       atomic_t delay;
+       atomic_t position;
+       u8 chip_id;
+};
+
+static struct fxas2100x_data *g_fxas2100x_data;
+
+static int fxas2100x_position_setting[8][3][3] = {
+       { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} },
+       { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },
+       { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+       { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} },
+       { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+       { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },
+       { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} },
+       { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} },
+};
+
+static int fxas2100x_data_convert(struct fxas2100x_data *pdata,
+               struct fxas2100x_data_axis *axis_data)
+{
+       short rawdata[3], data[3];
+       int i, j;
+       int position = atomic_read(&pdata->position);
+
+       if (position < 0 || position > 7)
+               position = 0;
+       rawdata[0] = axis_data->x;
+       rawdata[1] = axis_data->y;
+       rawdata[2] = axis_data->z;
+       for (i = 0; i < 3; i++) {
+               data[i] = 0;
+               for (j = 0; j < 3; j++)
+                       data[i] += rawdata[j] * fxas2100x_position_setting[position][i][j];
+       }
+       axis_data->x = data[0];
+       axis_data->y = data[1];
+       axis_data->z = data[2];
+       return 0;
+}
+
+static int fxas2100x_device_init(struct i2c_client *client)
+{
+       int result;
+       u8 val;
+       struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+       if (pdata->chip_id == FXAS21000_CHIP_ID)
+               val = (0x01 << 2); /* fxas21000 dr 200HZ */
+       else
+               val = (0x02 << 2); /* fxas21002 dr 200HZ */
+       result = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+       if (result < 0)
+               goto out;
+       atomic_set(&pdata->active, STANDBY);
+       return 0;
+out:
+       dev_err(&client->dev, "error when init fxas2100x:(%d)", result);
+       return result;
+}
+
+static int fxas2100x_change_mode(struct i2c_client *client, int mode)
+{
+       u8 val;
+       int ret;
+       if (mode == ACTIVED) {
+               val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+               val &= ~0x03;
+               val |= 0x02;
+               /* set bit 1 */
+               ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+       } else {
+               val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+               val &= (~0x03);
+               /* clear bit 0,1 */
+               ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+       }
+       return ret;
+}
+
+static int fxas2100x_set_delay(struct i2c_client *client, int delay)
+{
+       return 0;
+}
+
+static int fxas2100x_device_stop(struct i2c_client *client)
+{
+       u8 val;
+       val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+       val &= ~0x03;
+       i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+       return 0;
+}
+
+static int fxas2100x_read_data(struct fxas2100x_data *pdata,
+               struct fxas2100x_data_axis *data)
+{
+       struct i2c_client * client = pdata->client;
+       int x, y, z;
+       u8 tmp_data[FXAS2100X_BUF_SIZE];
+       int ret;
+
+       ret = i2c_smbus_read_i2c_block_data(client, FXAS2100X_OUT_X_MSB,
+                                           FXAS2100X_BUF_SIZE, tmp_data);
+       if (ret < FXAS2100X_BUF_SIZE) {
+               dev_err(&client->dev, "i2c block read failed\n");
+               return -EIO;
+       }
+       data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+       data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+       data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+       if (pdata->chip_id == FXAS21000_CHIP_ID) {
+               x = data->x;
+               y = data->y;
+               z = data->z;
+               x = x * 4 / 5;
+               y = y * 4 / 5;
+               z = z * 4 / 5;
+               data->x = x;
+               data->y = y;
+               data->z = z;
+       }
+
+       return 0;
+}
+
+/* fxas2100x miscdevice */
+static long fxas2100x_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct fxas2100x_data *pdata = file->private_data;
+       void __user *argp = (void __user *)arg;
+       struct fxas2100x_data_axis data;
+       long ret = 0;
+       short sdata[3];
+       int enable;
+       int delay;
+
+       if (!pdata) {
+               printk(KERN_ERR "FXAS2100X struct datt point is NULL.");
+               return -EFAULT;
+       }
+
+       switch (cmd) {
+       case SENSOR_GET_MODEL_NAME:
+               if (copy_to_user(argp, "FXAS2100X GYRO", strlen("FXAS2100X GYRO") + 1)) {
+                       printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed.");
+                       ret = -EFAULT;
+               }
+               break;
+       case SENSOR_GET_POWER_STATUS:
+               enable = atomic_read(&pdata->active);
+               if (copy_to_user(argp, &enable, sizeof(int))) {
+                       printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+                       ret = -EFAULT;
+               }
+               break;
+       case SENSOR_SET_POWER_STATUS:
+               if (copy_from_user(&enable, argp, sizeof(int))) {
+                       printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+                       ret = -EFAULT;
+               }
+               if (pdata->client) {
+                       ret = fxas2100x_change_mode(pdata->client, enable ? ACTIVED : STANDBY);
+                       if (!ret)
+                               atomic_set(&pdata->active, enable);
+               }
+               break;
+       case SENSOR_GET_DELAY_TIME:
+               delay = atomic_read(&pdata->delay);
+               if (copy_to_user(argp, &delay, sizeof(delay))) {
+                       printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+                       return -EFAULT;
+               }
+               break;
+       case SENSOR_SET_DELAY_TIME:
+               if (copy_from_user(&delay, argp, sizeof(int))) {
+                       printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+                       ret = -EFAULT;
+               }
+               if (pdata->client && delay > 0 && delay <= 500) {
+                       ret = fxas2100x_set_delay(pdata->client, delay);
+                       if (!ret)
+                               atomic_set(&pdata->delay, delay);
+               }
+               break;
+       case SENSOR_GET_RAW_DATA:
+               ret = fxas2100x_read_data(pdata, &data);
+               if (!ret) {
+                       fxas2100x_data_convert(pdata, &data);
+                       sdata[0] = data.x;
+                       sdata[1] = data.y;
+                       sdata[2] = data.z;
+                       if (copy_to_user(argp, sdata, sizeof(sdata))) {
+                               printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");
+                               ret = -EFAULT;
+                       }
+               }
+               break;
+       default:
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static int fxas2100x_open(struct inode *inode, struct file *file)
+{
+       file->private_data = g_fxas2100x_data;
+       return nonseekable_open(inode, file);
+}
+
+static int fxas2100x_release(struct inode *inode, struct file *file)
+{
+       /* note: releasing the wdt in NOWAYOUT-mode does not stop it */
+       return 0;
+}
+
+static const struct file_operations fxas2100x_fops = {
+       .owner = THIS_MODULE,
+       .open = fxas2100x_open,
+       .release = fxas2100x_release,
+       .unlocked_ioctl = fxas2100x_ioctl,
+};
+
+static struct miscdevice fxas2100x_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "FreescaleGyroscope",
+       .fops = &fxas2100x_fops,
+};
+
+static ssize_t fxas2100x_enable_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       int enable = 0;
+       enable = atomic_read(&pdata->active);
+       return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t fxas2100x_enable_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       struct i2c_client *client = pdata->client;
+       int ret;
+       unsigned long enable;
+
+       if (kstrtoul(buf, 10, &enable) < 0)
+               return -EINVAL;
+
+       enable = (enable > 0) ? 1 : 0;
+       ret = fxas2100x_change_mode(client, (enable > 0 ? ACTIVED : STANDBY));
+       if (!ret) {
+               atomic_set(&pdata->active, enable);
+               atomic_set(&pdata->active_poll, enable);
+               dev_err(dev, "mma enable setting active \n");
+       }
+       return count;
+}
+
+static ssize_t fxas2100x_poll_delay_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       int delay = 0;
+
+       delay = atomic_read(&pdata->delay);
+       return sprintf(buf, "%d\n", delay);
+}
+
+static ssize_t fxas2100x_poll_delay_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       struct i2c_client *client = pdata->client;
+       int ret;
+       int delay;
+
+       delay = simple_strtoul(buf, NULL, 10);
+       ret = fxas2100x_set_delay(client, delay);
+       if (!ret)
+               atomic_set(&pdata->delay, delay);
+       return count;
+}
+
+static ssize_t fxas2100x_position_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       int position = 0;
+
+       position = atomic_read(&pdata->position);
+       return sprintf(buf, "%d\n", position);
+}
+
+static ssize_t fxas2100x_position_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       int position;
+
+       position = simple_strtoul(buf, NULL, 10);
+       atomic_set(&pdata->position, position);
+       return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxas2100x_enable_show, fxas2100x_enable_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxas2100x_poll_delay_show, fxas2100x_poll_delay_store);
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxas2100x_position_show, fxas2100x_position_store);
+
+static struct attribute *fxas2100x_attributes[] = {
+       &dev_attr_enable.attr,
+       &dev_attr_poll_delay.attr,
+       &dev_attr_position.attr,
+       NULL
+};
+
+static const struct attribute_group fxas2100x_attr_group = {
+       .attrs  = fxas2100x_attributes,
+};
+
+static void fxas2100x_poll(struct input_polled_dev *dev)
+{
+       struct fxas2100x_data *pdata = g_fxas2100x_data;
+       struct input_dev *idev = pdata->input_polled->input;
+       struct fxas2100x_data_axis data;
+       int ret;
+
+       if (!(atomic_read(&pdata->active_poll)))
+               return;
+
+       ret = fxas2100x_read_data(pdata, &data);
+       if (!ret) {
+               fxas2100x_data_convert(pdata, &data);
+               input_report_abs(idev, ABS_X, data.x);
+               input_report_abs(idev, ABS_Y, data.y);
+               input_report_abs(idev, ABS_Z, data.z);
+               input_sync(idev);
+       }
+}
+
+static int fxas2100x_register_polled_device(struct fxas2100x_data *pdata)
+{
+       struct input_polled_dev *ipoll_dev;
+       struct input_dev *idev;
+       int error;
+
+       ipoll_dev = input_allocate_polled_device();
+       if (!ipoll_dev)
+               return -ENOMEM;
+
+       ipoll_dev->private = pdata;
+       ipoll_dev->poll = fxas2100x_poll;
+       ipoll_dev->poll_interval = FXAS2100X_POLL_INTERVAL;
+       ipoll_dev->poll_interval_min = FXAS2100X_POLL_MIN;
+       ipoll_dev->poll_interval_max = FXAS2100X_POLL_MAX;
+       idev = ipoll_dev->input;
+       idev->name = FXAS2100X_DRIVER;
+       idev->id.bustype = BUS_I2C;
+       idev->dev.parent = &pdata->client->dev;
+
+       idev->evbit[0] = BIT_MASK(EV_ABS);
+       input_set_abs_params(idev, ABS_X, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+       input_set_abs_params(idev, ABS_Y, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+       input_set_abs_params(idev, ABS_Z, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+
+       error = input_register_polled_device(ipoll_dev);
+       if (error) {
+               input_free_polled_device(ipoll_dev);
+               return error;
+       }
+
+       pdata->input_polled = ipoll_dev;
+       return 0;
+}
+
+static int fxas2100x_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       int result, chip_id;
+       struct fxas2100x_data *pdata;
+       struct i2c_adapter *adapter;
+
+       adapter = to_i2c_adapter(client->dev.parent);
+       result = i2c_check_functionality(adapter,
+                                        I2C_FUNC_SMBUS_BYTE |
+                                        I2C_FUNC_SMBUS_BYTE_DATA);
+       if (!result)
+               goto err_out;
+
+       chip_id = i2c_smbus_read_byte_data(client, FXAS2100X_WHO_AM_I);
+       if (chip_id != FXAS21000_CHIP_ID && chip_id != FXAS21002_CHID_ID_1 &&
+           chip_id != FXAS21002_CHID_ID_2) {
+               dev_err(&client->dev,
+                       "read chip ID 0x%x is not equal to 0x%x for fxas21000 or 0x%x/0x%x fxas21002!\n",
+                       chip_id, FXAS21000_CHIP_ID, FXAS21002_CHID_ID_1, FXAS21002_CHID_ID_2);
+               result = -EINVAL;
+               goto err_out;
+       }
+
+       pdata = kzalloc(sizeof(struct fxas2100x_data), GFP_KERNEL);
+       if (!pdata) {
+               result = -ENOMEM;
+               dev_err(&client->dev, "alloc data memory error!\n");
+               goto err_out;
+       }
+
+       /* Initialize the FXAS2100X chip */
+       g_fxas2100x_data = pdata;
+       pdata->client = client;
+       pdata->chip_id = chip_id;
+       atomic_set(&pdata->delay, FXAS2100X_DELAY_DEFAULT);
+       atomic_set(&pdata->position, FXAS2100X_POSITION_DEFAULT);
+       i2c_set_clientdata(client, pdata);
+       result = misc_register(&fxas2100x_device);
+       if (result != 0) {
+               dev_err(&client->dev, "register acc miscdevice error");
+               goto err_regsiter_misc;
+       }
+
+       /* for debug */
+       if (client->irq <= 0) {
+               result = fxas2100x_register_polled_device(g_fxas2100x_data);
+               if (result)
+                       dev_err(&client->dev,
+                               "IRQ GPIO conf. error %d, error %d\n",
+                               client->irq, result);
+       }
+
+       result = sysfs_create_group(&fxas2100x_device.this_device->kobj,
+                                   &fxas2100x_attr_group);
+       if (result) {
+               dev_err(&client->dev, "create device file failed!\n");
+               result = -EINVAL;
+               goto err_create_sysfs;
+       }
+       fxas2100x_device_init(client);
+       dev_info(&client->dev, "fxas2100x device driver probe successfully\n");
+       return 0;
+err_create_sysfs:
+       misc_deregister(&fxas2100x_device);
+err_regsiter_misc:
+       kfree(pdata);
+err_out:
+       return result;
+}
+
+static int fxas2100x_remove(struct i2c_client *client)
+{
+       struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+       fxas2100x_device_stop(client);
+       if (client->irq <= 0) {
+               input_unregister_polled_device(pdata->input_polled);
+               input_free_polled_device(pdata->input_polled);
+       }
+       misc_deregister(&fxas2100x_device);
+       if (pdata != NULL)
+               kfree(pdata);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fxas2100x_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+
+       if (atomic_read(&pdata->active))
+               fxas2100x_device_stop(client);
+       return 0;
+}
+
+static int fxas2100x_resume(struct device *dev)
+{
+       int val = 0;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+
+       if (atomic_read(&pdata->active)) {
+               val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+               val &= ~0x03;
+               val |= 0x02;
+               i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+       }
+       return 0;
+
+}
+#endif
+
+static const struct i2c_device_id fxas2100x_id[] = {
+       { "fxas2100x", 0 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, fxas2100x_id);
+
+static SIMPLE_DEV_PM_OPS(fxas2100x_pm_ops, fxas2100x_suspend, fxas2100x_resume);
+static struct i2c_driver fxas2100x_driver = {
+       .driver         = {
+               .name   = FXAS2100X_DRIVER,
+               .owner  = THIS_MODULE,
+               .pm     = &fxas2100x_pm_ops,
+       },
+       .probe          = fxas2100x_probe,
+       .remove         = fxas2100x_remove,
+       .id_table       = fxas2100x_id,
+};
+
+module_i2c_driver(fxas2100x_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("FXAS2100X 3-Axis Gyrosope Sensor driver");
+MODULE_LICENSE("GPL");