android_kernel_modules_leno.../drivers/hwmon/l3g4200d_poll.c

837 lines
20 KiB
C

/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
*
* File Name : l3g4200d_poll.c
* Authors : MH - C&I BU - Application Team
* : Carmine Iascone (carmine.iascone@st.com)
* : Matteo Dameno (matteo.dameno@st.com)
* : Both authors are willing to be considered the contact
* : and update points for the driver.
* Version : V 1.1 sysfs
* Date : 2011/02/28
* Description : L3G4200D digital output gyroscope sensor API
*
********************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
********************************************************************************
* REVISON HISTORY
*
* VERSION | DATE | AUTHORS | DESCRIPTION
* 1.0 | 2010/11/19 | Carmine Iascone | First Release
* 1.1 | 2011/02/28 | Matteo Dameno | Self Test Added
*******************************************************************************/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/input/l3g4200d_poll.h>
#include <linux/delay.h>
/* l3g4200d gyroscope registers */
#define WHO_AM_I 0x0F
#define CTRL_REG1 0x20 /* CTRL REG1 */
#define CTRL_REG2 0x21 /* CTRL REG2 */
#define CTRL_REG3 0x22 /* CTRL_REG3 */
#define CTRL_REG4 0x23 /* CTRL_REG4 */
#define CTRL_REG5 0x24 /* CTRL_REG5 */
/* CTRL_REG1 */
#define PM_ON 0x08
#define ENABLE_ALL_AXES 0x07
#define BW00 0x00
#define BW01 0x10
#define BW10 0x20
#define BW11 0x30
#define ODR100 0x00 /* ODR = 100Hz */
#define ODR200 0x40 /* ODR = 200Hz */
#define ODR400 0x80 /* ODR = 400Hz */
#define ODR800 0xC0 /* ODR = 800Hz */
#define ODR_MASK 0xF0
/* CTRL_REG4 bits */
#define FS_MASK 0x30
#define SELFTEST_MASK 0x06
#define L3G4200D_SELFTEST_DIS 0x00
#define L3G4200D_SELFTEST_EN_POS 0x02
#define L3G4200D_SELFTEST_EN_NEG 0x04
#define AXISDATA_REG 0x28
#define AUTO_INCREMENT 0x80
/* RESUME STATE INDICES */
#define RES_CTRL_REG1 0
#define RES_CTRL_REG2 1
#define RES_CTRL_REG3 2
#define RES_CTRL_REG4 3
#define RES_CTRL_REG5 4
#define RESUME_ENTRIES 5
#define MAX_POLL_DELAY 500
#define DEBUG 1
/** Registers Contents */
#define WHOAMI_L3G4200D 0x00D3 /* Expected content for WAI register*/
#define WHOAMI_L3GD20 0x00D4 /* WAI register for l3gd20 */
#define WHOAMI_L3GD20H 0x00D7 /* WAI register for l3gd20h */
/* After device enable a short delay
* is needed for device to be stable.
*/
#define L3GD20_STABLE_DELAY 100
#define L3G4200D_STABLE_DELAY 300
struct output_rate {
int poll_rate_ms;
u8 mask;
};
static const struct output_rate odr_table[] = {
{2, ODR800|BW10},
{3, ODR400|BW01},
{5, ODR200|BW00},
{10, ODR100|BW00},
};
struct l3g4200d_data {
struct i2c_client *client;
struct l3g4200d_gyr_platform_data *pdata;
struct mutex lock;
struct input_dev *input_dev;
u8 resume_state[RESUME_ENTRIES];
struct delayed_work work;
int need_resume;
int hw_init_delay;
};
static void l3g4200d_update_odr_bits(struct l3g4200d_data *gyro)
{
int i;
/* find the lowest ODR that could meet the poll interval requirement.
* If couldn't find one, use the highest one.
*/
for (i = ARRAY_SIZE(odr_table) - 1; i > 0; i--) {
if (odr_table[i].poll_rate_ms <= gyro->pdata->poll_interval)
break;
}
gyro->resume_state[RES_CTRL_REG1] &= (~ODR_MASK);
gyro->resume_state[RES_CTRL_REG1] |= odr_table[i].mask;
}
static int l3g4200d_hw_init(struct l3g4200d_data *gyro)
{
int ret;
/* check if the chip reports the correct id */
ret = i2c_smbus_read_byte_data(gyro->client, WHO_AM_I);
if (ret < 0)
return ret;
switch (ret) {
case WHOAMI_L3G4200D:
gyro->hw_init_delay = L3G4200D_STABLE_DELAY;
break;
case WHOAMI_L3GD20:
case WHOAMI_L3GD20H:
gyro->hw_init_delay = L3GD20_STABLE_DELAY;
break;
default:
dev_err(&gyro->client->dev, "Invalid device id, %x", ret);
return -EINVAL;
}
/* set default settings, and put gyro in power down mode */
gyro->resume_state[RES_CTRL_REG1] = ENABLE_ALL_AXES;
gyro->resume_state[RES_CTRL_REG2] = 0x00;
gyro->resume_state[RES_CTRL_REG3] = 0x00;
gyro->resume_state[RES_CTRL_REG4] = gyro->pdata->fs_range;
gyro->resume_state[RES_CTRL_REG5] = 0x00;
l3g4200d_update_odr_bits(gyro);
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG1,
gyro->resume_state[RES_CTRL_REG1]);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG2,
gyro->resume_state[RES_CTRL_REG2]);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG3,
gyro->resume_state[RES_CTRL_REG3]);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG4,
gyro->resume_state[RES_CTRL_REG4]);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG5,
gyro->resume_state[RES_CTRL_REG5]);
if (ret < 0)
return ret;
return ret;
}
static void l3g4200d_queue_delayed_work(struct l3g4200d_data *gyro, int more)
{
unsigned long delay =
msecs_to_jiffies(gyro->pdata->poll_interval + more);
schedule_delayed_work(&gyro->work, delay);
}
static void l3g4200d_report_data(struct l3g4200d_data *gyro)
{
u8 buf[6] = { 0 };
s16 hw_d[3];
s16 x, y, z;
int ret;
ret = i2c_smbus_read_i2c_block_data(gyro->client,
AUTO_INCREMENT | AXISDATA_REG,
sizeof(buf), &buf[0]);
if (ret < 0) {
dev_err(&gyro->client->dev, "Failed to read axis data.\n");
return;
}
hw_d[0] = (s16) ((buf[1] << 8) | buf[0]);
hw_d[1] = (s16) ((buf[3] << 8) | buf[2]);
hw_d[2] = (s16) ((buf[5] << 8) | buf[4]);
x = ((gyro->pdata->negate_x) ? (-hw_d[gyro->pdata->axis_map_x])
: (hw_d[gyro->pdata->axis_map_x]));
y = ((gyro->pdata->negate_y) ? (-hw_d[gyro->pdata->axis_map_y])
: (hw_d[gyro->pdata->axis_map_y]));
z = ((gyro->pdata->negate_z) ? (-hw_d[gyro->pdata->axis_map_z])
: (hw_d[gyro->pdata->axis_map_z]));
#ifdef DEBUG
{
struct timeval now;
jiffies_to_timeval(jiffies, &now);
dev_dbg(&gyro->client->dev, "%ld.%ld: X=%d, Y=%d, Z=%d",
now.tv_sec, now.tv_usec,
(int) x,
(int) y,
(int) z);
}
#endif
input_report_rel(gyro->input_dev, REL_X, x);
input_report_rel(gyro->input_dev, REL_Y, y);
input_report_rel(gyro->input_dev, REL_Z, z);
input_sync(gyro->input_dev);
}
static int l3g4200d_enabled(struct l3g4200d_data *gyro)
{
return gyro->resume_state[RES_CTRL_REG1] & PM_ON;
}
static void l3g4200d_poll_work(struct work_struct *work)
{
struct l3g4200d_data *gyro =
container_of(work, struct l3g4200d_data, work.work);
mutex_lock(&gyro->lock);
/* there is the possibility that the device is already disabled
* before this delayed work is executed.
*/
if (!l3g4200d_enabled(gyro))
goto leave;
l3g4200d_report_data(gyro);
l3g4200d_queue_delayed_work(gyro, 0);
leave:
mutex_unlock(&gyro->lock);
}
static int l3g4200d_enable(struct l3g4200d_data *gyro)
{
int err;
if (l3g4200d_enabled(gyro))
return 0;
/* Change power down mode bit of CTRL_REG1 to enable the gyro chip */
gyro->resume_state[RES_CTRL_REG1] |= PM_ON;
err = i2c_smbus_write_byte_data(gyro->client, CTRL_REG1,
gyro->resume_state[RES_CTRL_REG1]);
if (err < 0) {
dev_err(&gyro->client->dev, "Failed to enable gyro.\n");
return err;
}
l3g4200d_queue_delayed_work(gyro, gyro->hw_init_delay);
return 0;
}
static int l3g4200d_disable(struct l3g4200d_data *gyro)
{
int err;
if (!l3g4200d_enabled(gyro))
return 0;
/* Change power down mode bit of CTRL_REG1 to disable the gyro chip */
gyro->resume_state[RES_CTRL_REG1] &= ~PM_ON;
err = i2c_smbus_write_byte_data(gyro->client, CTRL_REG1,
gyro->resume_state[RES_CTRL_REG1]);
if (err < 0) {
dev_err(&gyro->client->dev, "Failed to disable gyro.\n");
return err;
}
cancel_delayed_work(&gyro->work);
return 0;
}
static ssize_t attr_polling_rate_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int val;
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
mutex_lock(&gyro->lock);
val = gyro->pdata->poll_interval;
mutex_unlock(&gyro->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_polling_rate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
unsigned long interval_ms;
int saved_interval;
int err;
if (strict_strtoul(buf, 10, &interval_ms))
return -EINVAL;
if (interval_ms < (unsigned long) odr_table[0].poll_rate_ms) {
dev_info(dev, "polling interval is too small, set it to %d\n",
odr_table[0].poll_rate_ms);
interval_ms = odr_table[0].poll_rate_ms;
}
/* set max poll interval to be 500 ms */
if (interval_ms > MAX_POLL_DELAY) {
dev_info(dev, "polling interval is too big, set it to 500\n");
interval_ms = MAX_POLL_DELAY;
}
mutex_lock(&gyro->lock);
saved_interval = gyro->pdata->poll_interval;
gyro->pdata->poll_interval = (int)interval_ms;
l3g4200d_update_odr_bits(gyro);
err = i2c_smbus_write_byte_data(gyro->client, CTRL_REG1,
gyro->resume_state[RES_CTRL_REG1]);
if (err < 0) {
dev_err(&gyro->client->dev, "Failed to change poll interval.\n");
gyro->pdata->poll_interval = saved_interval;
l3g4200d_update_odr_bits(gyro);
mutex_unlock(&gyro->lock);
return -EIO;
}
mutex_unlock(&gyro->lock);
return size;
}
static ssize_t attr_range_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
int range = 0;
u8 val;
mutex_lock(&gyro->lock);
val = gyro->resume_state[RES_CTRL_REG4] & FS_MASK;
switch (val) {
case L3G4200D_GYR_FS_250DPS:
range = 250;
break;
case L3G4200D_GYR_FS_500DPS:
range = 500;
break;
case L3G4200D_GYR_FS_2000DPS:
default:
range = 2000;
break;
}
mutex_unlock(&gyro->lock);
return sprintf(buf, "%d\n", range);
}
static ssize_t attr_range_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
unsigned long val;
u8 saved;
u8 range_bits;
int ret;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
if (val != 250 && val != 500 && val != 2000)
return -EINVAL;
mutex_lock(&gyro->lock);
switch (val) {
case 250:
range_bits = L3G4200D_GYR_FS_250DPS;
break;
case 500:
range_bits = L3G4200D_GYR_FS_500DPS;
break;
case 2000:
default:
range_bits = L3G4200D_GYR_FS_2000DPS;
break;
}
saved = gyro->resume_state[RES_CTRL_REG4];
gyro->resume_state[RES_CTRL_REG4] &= ~FS_MASK;
gyro->resume_state[RES_CTRL_REG4] |= range_bits;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG4,
gyro->resume_state[RES_CTRL_REG4]);
if (ret < 0) {
dev_err(&gyro->client->dev, "Failed to change fs range.\n");
gyro->resume_state[RES_CTRL_REG4] = saved;
mutex_unlock(&gyro->lock);
return ret;
}
mutex_unlock(&gyro->lock);
return size;
}
static ssize_t attr_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
int val;
mutex_lock(&gyro->lock);
val = (gyro->resume_state[RES_CTRL_REG1] & PM_ON) ? 1 : 0;
mutex_unlock(&gyro->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
unsigned long val;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
mutex_lock(&gyro->lock);
if (val)
l3g4200d_enable(gyro);
else
l3g4200d_disable(gyro);
mutex_unlock(&gyro->lock);
return size;
}
static ssize_t attr_get_selftest(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
u8 self_test_bits;
int val;
mutex_lock(&gyro->lock);
self_test_bits = gyro->resume_state[RES_CTRL_REG4] & SELFTEST_MASK;
mutex_unlock(&gyro->lock);
switch (self_test_bits) {
case L3G4200D_SELFTEST_EN_POS:
val = 1;
break;
case L3G4200D_SELFTEST_EN_NEG:
val = -1;
break;
default:
val = 0;
break;
}
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_selftest(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
long val;
u8 saved;
int ret;
if (strict_strtol(buf, 10, &val))
return -EINVAL;
mutex_lock(&gyro->lock);
saved = gyro->resume_state[RES_CTRL_REG4];
gyro->resume_state[RES_CTRL_REG4] &= ~SELFTEST_MASK;
if (val < 0)
gyro->resume_state[RES_CTRL_REG4] |= L3G4200D_SELFTEST_EN_NEG;
else if (val > 0)
gyro->resume_state[RES_CTRL_REG4] |= L3G4200D_SELFTEST_EN_POS;
else
gyro->resume_state[RES_CTRL_REG4] |= L3G4200D_SELFTEST_DIS;
ret = i2c_smbus_write_byte_data(gyro->client, CTRL_REG4,
gyro->resume_state[RES_CTRL_REG4]);
if (ret < 0) {
dev_err(&gyro->client->dev, "Failed to change fs range.\n");
gyro->resume_state[RES_CTRL_REG4] = saved;
mutex_unlock(&gyro->lock);
return ret;
}
mutex_unlock(&gyro->lock);
return size;
}
static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
ssize_t data_size = 0;
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
int rc;
int i;
u8 ctl_regs[5] = { 0 };
/* read and display the 5 control registers */
mutex_lock(&gyro->lock);
rc = i2c_smbus_read_i2c_block_data(gyro->client,
AUTO_INCREMENT | CTRL_REG1,
sizeof(ctl_regs), &ctl_regs[0]);
if (rc < 0) {
dev_err(&gyro->client->dev,
"Failed to read control register data.\n");
mutex_unlock(&gyro->lock);
return -EINVAL;
}
mutex_unlock(&gyro->lock);
for (i = 0; i < 5; ++i)
data_size += sprintf(&buf[data_size], "CTRL_REG%d=0x%x\n",
i, (unsigned int)ctl_regs[i]);
return data_size;
}
static struct device_attribute attributes[] = {
__ATTR(poll, 0644, attr_polling_rate_show, attr_polling_rate_store),
__ATTR(enable, 0644, attr_enable_show, attr_enable_store),
__ATTR(range, 0644, attr_range_show, attr_range_store),
__ATTR(enable_selftest, 0644, attr_get_selftest, attr_set_selftest),
__ATTR(registers, 0400, attr_reg_get, NULL),
};
static int create_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
if (device_create_file(dev, attributes + i))
goto error;
return 0;
error:
for (i = i - 1; i >= 0; i--)
device_remove_file(dev, attributes + i);
dev_err(dev, "%s:Unable to create interface\n", __func__);
return -1;
}
static int remove_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(dev, attributes + i);
return 0;
}
static int l3g4200d_input_init(struct l3g4200d_data *gyro)
{
int err;
struct device *dev = &gyro->client->dev;
gyro->input_dev = input_allocate_device();
if (!gyro->input_dev) {
dev_err(dev, "input device allocation failed.\n");
return -ENOMEM;
}
gyro->input_dev->name = L3G4200D_GYR_DEV_NAME;
gyro->input_dev->id.bustype = BUS_I2C;
gyro->input_dev->dev.parent = dev;
input_set_drvdata(gyro->input_dev, gyro);
set_bit(EV_REL, gyro->input_dev->evbit);
set_bit(REL_X, gyro->input_dev->relbit);
set_bit(REL_Y, gyro->input_dev->relbit);
set_bit(REL_Z, gyro->input_dev->relbit);
err = input_register_device(gyro->input_dev);
if (err) {
dev_err(dev, "unable to register input device.\n");
input_free_device(gyro->input_dev);
return err;
}
return 0;
}
static int l3g4200d_validate_pdata(struct l3g4200d_data *gyro)
{
if (gyro->pdata->axis_map_x > 2 ||
gyro->pdata->axis_map_y > 2 ||
gyro->pdata->axis_map_z > 2) {
dev_err(&gyro->client->dev,
"invalid axis_map value x:%u y:%u z%u\n",
gyro->pdata->axis_map_x,
gyro->pdata->axis_map_y,
gyro->pdata->axis_map_z);
return -EINVAL;
}
/* Only allow 0 and 1 for negation boolean flag */
if (gyro->pdata->negate_x > 1 ||
gyro->pdata->negate_y > 1 ||
gyro->pdata->negate_z > 1) {
dev_err(&gyro->client->dev,
"invalid negate value x:%u y:%u z:%u\n",
gyro->pdata->negate_x,
gyro->pdata->negate_y,
gyro->pdata->negate_z);
return -EINVAL;
}
/* Enforce minimum polling interval */
if (gyro->pdata->poll_interval < gyro->pdata->min_interval) {
dev_err(&gyro->client->dev,
"minimum poll interval violated\n");
return -EINVAL;
}
return 0;
}
static int l3g4200d_probe(struct i2c_client *client,
const struct i2c_device_id *devid)
{
int err;
struct l3g4200d_data *gyro;
dev_info(&client->dev, "probe start.\n");
if (client->dev.platform_data == NULL) {
dev_err(&client->dev, "platform data is NULL. exiting.\n");
err = -ENODEV;
goto err_out;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(&client->dev, "client not i2c capable.\n");
err = -ENODEV;
goto err_out;
}
gyro = kzalloc(sizeof(*gyro), GFP_KERNEL);
if (gyro == NULL) {
dev_err(&client->dev, "failed to allocate memory.\n");
err = -ENOMEM;
goto err_out;
}
gyro->pdata = kmalloc(sizeof(*gyro->pdata), GFP_KERNEL);
if (gyro->pdata == NULL) {
dev_err(&client->dev, "failed to allocate memory for pdata.");
err = -ENOMEM;
goto err_free_gyro;
}
memcpy(gyro->pdata, client->dev.platform_data, sizeof(*gyro->pdata));
err = l3g4200d_validate_pdata(gyro);
if (err < 0) {
dev_err(&client->dev, "failed to validate platform data.\n");
goto err_free_pdata;
}
gyro->client = client;
i2c_set_clientdata(client, gyro);
err = l3g4200d_input_init(gyro);
if (err < 0)
goto err_free_pdata;
err = l3g4200d_hw_init(gyro);
if (err < 0) {
dev_err(&client->dev, "failed to init l3g4200d hardware.\n");
goto err_clean_input;
}
err = create_sysfs_interfaces(&client->dev);
if (err < 0)
goto err_clean_input;
mutex_init(&gyro->lock);
INIT_DELAYED_WORK(&gyro->work, l3g4200d_poll_work);
dev_info(&client->dev, "probed.\n");
return 0;
err_clean_input:
input_unregister_device(gyro->input_dev);
err_free_pdata:
kfree(gyro->pdata);
err_free_gyro:
kfree(gyro);
err_out:
dev_err(&client->dev, "Driver Initialization failed, %d\n", err);
return err;
}
static int l3g4200d_remove(struct i2c_client *client)
{
struct l3g4200d_data *gyro = i2c_get_clientdata(client);
dev_info(&client->dev, "L3G4200D driver removing\n");
remove_sysfs_interfaces(&client->dev);
mutex_lock(&gyro->lock);
l3g4200d_disable(gyro);
mutex_unlock(&gyro->lock);
/* there may be still a delayed work in execution, we must wait for
* its completion before we could reclaim resources.
*/
cancel_delayed_work_sync(&gyro->work);
mutex_destroy(&gyro->lock);
input_unregister_device(gyro->input_dev);
kfree(gyro->pdata);
kfree(gyro);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int l3g4200d_suspend(struct device *dev)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
mutex_lock(&gyro->lock);
gyro->need_resume = l3g4200d_enabled(gyro);
l3g4200d_disable(gyro);
mutex_unlock(&gyro->lock);
return 0;
}
static int l3g4200d_resume(struct device *dev)
{
struct l3g4200d_data *gyro = dev_get_drvdata(dev);
mutex_lock(&gyro->lock);
if (gyro->need_resume)
l3g4200d_enable(gyro);
mutex_unlock(&gyro->lock);
return 0;
}
static const struct dev_pm_ops l3g4200d_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(l3g4200d_suspend,
l3g4200d_resume)
};
#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id l3g4200d_id[] = {
{ L3G4200D_GYR_DEV_NAME , 0 },
{ L3GD20H_GYR_DEV_NAME , 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, l3g4200d_id);
static struct i2c_driver l3g4200d_driver = {
.driver = {
.owner = THIS_MODULE,
.name = L3G4200D_GYR_DEV_NAME,
#ifdef CONFIG_PM_SLEEP
.pm = &l3g4200d_pm_ops,
#endif /* CONFIG_PM_SLEEP */
},
.probe = l3g4200d_probe,
.remove = l3g4200d_remove,
.id_table = l3g4200d_id,
};
static int __init l3g4200d_init(void)
{
pr_info("%s: l3g4200d polling driver init\n", L3G4200D_GYR_DEV_NAME);
return i2c_add_driver(&l3g4200d_driver);
}
static void __exit l3g4200d_exit(void)
{
pr_info("L3G4200D polling driver exit\n");
i2c_del_driver(&l3g4200d_driver);
return;
}
module_init(l3g4200d_init);
module_exit(l3g4200d_exit);
MODULE_DESCRIPTION("l3g4200d digital gyroscope sysfs driver");
MODULE_AUTHOR("Matteo Dameno, Carmine Iascone, STMicroelectronics");
MODULE_LICENSE("GPL");