lkml.org 
[lkml]   [2011]   [Jun]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 03/11] misc: mpu3050 /dev/mpu implementation.
    Date
    Implements i2c probing, receives registration of slaves, handles file
    operations, and power management.

    Signed-off-by: Nathan Royer <nroyer@invensense.com>
    ---
    drivers/misc/inv_mpu/mpu-dev.c | 1247 ++++++++++++++++++++++++++++++++++++++++
    drivers/misc/inv_mpu/mpu-dev.h | 36 ++
    2 files changed, 1283 insertions(+), 0 deletions(-)
    create mode 100644 drivers/misc/inv_mpu/mpu-dev.c
    create mode 100644 drivers/misc/inv_mpu/mpu-dev.h

    diff --git a/drivers/misc/inv_mpu/mpu-dev.c b/drivers/misc/inv_mpu/mpu-dev.c
    new file mode 100644
    index 0000000..977631d
    --- /dev/null
    +++ b/drivers/misc/inv_mpu/mpu-dev.c
    @@ -0,0 +1,1247 @@
    +/*
    + $License:
    + Copyright (C) 2011 InvenSense Corporation, 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, see <http://www.gnu.org/licenses/>.
    + $
    + */
    +#include <linux/i2c.h>
    +#include <linux/i2c-dev.h>
    +#include <linux/interrupt.h>
    +#include <linux/module.h>
    +#include <linux/moduleparam.h>
    +#include <linux/kernel.h>
    +#include <linux/init.h>
    +#include <linux/stat.h>
    +#include <linux/irq.h>
    +#include <linux/gpio.h>
    +#include <linux/signal.h>
    +#include <linux/miscdevice.h>
    +#include <linux/slab.h>
    +#include <linux/version.h>
    +#include <linux/pm.h>
    +#include <linux/mutex.h>
    +#include <linux/suspend.h>
    +#include <linux/poll.h>
    +
    +#include <linux/errno.h>
    +#include <linux/fs.h>
    +#include <linux/mm.h>
    +#include <linux/sched.h>
    +#include <linux/wait.h>
    +#include <linux/uaccess.h>
    +#include <linux/io.h>
    +
    +#include "mpuirq.h"
    +#include "slaveirq.h"
    +#include "mlsl.h"
    +#include "mldl_cfg.h"
    +#include <linux/mpu.h>
    +
    +
    +/* Platform data for the MPU */
    +struct mpu_private_data {
    + struct miscdevice dev;
    + struct i2c_client *client;
    +
    + /* mldl_cfg data */
    + struct mldl_cfg mldl_cfg;
    + struct mpu_ram mpu_ram;
    + struct mpu_gyro_cfg mpu_gyro_cfg;
    + struct mpu_offsets mpu_offsets;
    + struct mpu_chip_info mpu_chip_info;
    + struct inv_mpu_cfg inv_mpu_cfg;
    + struct inv_mpu_state inv_mpu_state;
    +
    + struct mutex mutex;
    + wait_queue_head_t mpu_event_wait;
    + struct completion completion;
    + struct timer_list timeout;
    + struct notifier_block nb;
    + struct mpuirq_data mpu_pm_event;
    + int response_timeout; /* In seconds */
    + unsigned long event;
    + int pid;
    + struct module *slave_modules[EXT_SLAVE_NUM_TYPES];
    +};
    +
    +struct mpu_private_data *mpu_private_data;
    +
    +static void mpu_pm_timeout(u_long data)
    +{
    + struct mpu_private_data *mpu = (struct mpu_private_data *)data;
    + struct i2c_client *client = mpu->client;
    + dev_dbg(&client->adapter->dev, "%s\n", __func__);
    + complete(&mpu->completion);
    +}
    +
    +static int mpu_pm_notifier_callback(struct notifier_block *nb,
    + unsigned long event, void *unused)
    +{
    + struct mpu_private_data *mpu =
    + container_of(nb, struct mpu_private_data, nb);
    + struct i2c_client *client = mpu->client;
    + struct timeval event_time;
    + dev_dbg(&client->adapter->dev, "%s: %ld\n", __func__, event);
    +
    + /* Prevent the file handle from being closed before we initialize
    + the completion event */
    + mutex_lock(&mpu->mutex);
    + if (!(mpu->pid) ||
    + (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) {
    + mutex_unlock(&mpu->mutex);
    + return NOTIFY_OK;
    + }
    +
    + do_gettimeofday(&event_time);
    + mpu->mpu_pm_event.interruptcount++;
    + mpu->mpu_pm_event.irqtime =
    + (((long long)event_time.tv_sec) << 32) + event_time.tv_usec;
    + mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT;
    + mpu->mpu_pm_event.data = mpu->event;
    +
    + if (event == PM_SUSPEND_PREPARE)
    + mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE;
    + if (event == PM_POST_SUSPEND)
    + mpu->event = MPU_PM_EVENT_POST_SUSPEND;
    +
    + if (mpu->response_timeout > 0) {
    + mpu->timeout.expires = jiffies + mpu->response_timeout * HZ;
    + add_timer(&mpu->timeout);
    + }
    + INIT_COMPLETION(mpu->completion);
    + mutex_unlock(&mpu->mutex);
    +
    + wake_up_interruptible(&mpu->mpu_event_wait);
    + wait_for_completion(&mpu->completion);
    + del_timer_sync(&mpu->timeout);
    + dev_dbg(&client->adapter->dev, "%s: %ld DONE\n", __func__, event);
    + return NOTIFY_OK;
    +}
    +
    +static int mpu_dev_open(struct inode *inode, struct file *file)
    +{
    + struct mpu_private_data *mpu =
    + container_of(file->private_data, struct mpu_private_data, dev);
    + struct i2c_client *client = mpu->client;
    + int result;
    + int ii;
    + dev_dbg(&client->adapter->dev, "%s\n", __func__);
    + dev_dbg(&client->adapter->dev, "current->pid %d\n", current->pid);
    +
    + result = mutex_lock_interruptible(&mpu->mutex);
    + if (mpu->pid) {
    + mutex_unlock(&mpu->mutex);
    + return -EBUSY;
    + }
    + mpu->pid = current->pid;
    +
    + /* Reset the sensors to the default */
    + if (result) {
    + dev_err(&client->adapter->dev,
    + "%s: mutex_lock_interruptible returned %d\n",
    + __func__, result);
    + return result;
    + }
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++)
    + __module_get(mpu->slave_modules[ii]);
    +
    + mutex_unlock(&mpu->mutex);
    + return 0;
    +}
    +
    +/* close function - called when the "file" /dev/mpu is closed in userspace */
    +static int mpu_release(struct inode *inode, struct file *file)
    +{
    + struct mpu_private_data *mpu =
    + container_of(file->private_data, struct mpu_private_data, dev);
    + struct i2c_client *client = mpu->client;
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + int result = 0;
    + int ii;
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    +
    + mutex_lock(&mpu->mutex);
    + mldl_cfg->inv_mpu_cfg->requested_sensors = 0;
    + result = inv_mpu_suspend(mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + INV_ALL_SENSORS);
    + mpu->pid = 0;
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++)
    + module_put(mpu->slave_modules[ii]);
    +
    + mutex_unlock(&mpu->mutex);
    + complete(&mpu->completion);
    + dev_dbg(&client->adapter->dev, "mpu_release\n");
    +
    + return result;
    +}
    +
    +/* read function called when from /dev/mpu is read. Read from the FIFO */
    +static ssize_t mpu_read(struct file *file,
    + char __user *buf, size_t count, loff_t *offset)
    +{
    + struct mpu_private_data *mpu =
    + container_of(file->private_data, struct mpu_private_data, dev);
    + struct i2c_client *client = mpu->client;
    + size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long);
    + int err;
    +
    + if (!mpu->event && (!(file->f_flags & O_NONBLOCK)))
    + wait_event_interruptible(mpu->mpu_event_wait, mpu->event);
    +
    + if (!mpu->event || !buf
    + || count < sizeof(mpu->mpu_pm_event) + sizeof(unsigned long))
    + return 0;
    +
    + err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event));
    + if (err) {
    + dev_err(&client->adapter->dev,
    + "Copy to user returned %d\n", err);
    + return -EFAULT;
    + }
    + mpu->event = 0;
    + return len;
    +}
    +
    +static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll)
    +{
    + struct mpu_private_data *mpu =
    + container_of(file->private_data, struct mpu_private_data, dev);
    + int mask = 0;
    +
    + poll_wait(file, &mpu->mpu_event_wait, poll);
    + if (mpu->event)
    + mask |= POLLIN | POLLRDNORM;
    + return mask;
    +}
    +
    +static int mpu_dev_ioctl_get_ext_slave_platform_data(
    + struct i2c_client *client,
    + struct ext_slave_platform_data __user *arg)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct ext_slave_platform_data *pdata_slave;
    + struct ext_slave_platform_data local_pdata_slave;
    +
    + if (copy_from_user(&local_pdata_slave, arg, sizeof(local_pdata_slave)))
    + return -EFAULT;
    +
    + if (local_pdata_slave.type >= EXT_SLAVE_NUM_TYPES)
    + return -EINVAL;
    +
    + pdata_slave = mpu->mldl_cfg.pdata_slave[local_pdata_slave.type];
    + /* All but private data and irq_data */
    + if (!pdata_slave)
    + return -ENODEV;
    + if (copy_to_user(arg, pdata_slave, sizeof(*pdata_slave)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +static int mpu_dev_ioctl_get_mpu_platform_data(
    + struct i2c_client *client,
    + struct mpu_platform_data __user *arg)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct mpu_platform_data *pdata = mpu->mldl_cfg.pdata;
    +
    + if (copy_to_user(arg, pdata, sizeof(pdata)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +static int mpu_dev_ioctl_get_ext_slave_descr(
    + struct i2c_client *client,
    + struct ext_slave_descr __user *arg)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct ext_slave_descr *slave;
    + struct ext_slave_descr local_slave;
    +
    + if (copy_from_user(&local_slave, arg, sizeof(local_slave)))
    + return -EFAULT;
    +
    + if (local_slave.type >= EXT_SLAVE_NUM_TYPES)
    + return -EINVAL;
    +
    + slave = mpu->mldl_cfg.slave[local_slave.type];
    + /* All but private data and irq_data */
    + if (!slave)
    + return -ENODEV;
    + if (copy_to_user(arg, slave, sizeof(*slave)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +
    +/**
    + * slave_config() - Pass a requested slave configuration to the slave sensor
    + *
    + * @adapter the adaptor to use to communicate with the slave
    + * @mldl_cfg the mldl configuration structuer
    + * @slave pointer to the slave descriptor
    + * @usr_config The configuration to pass to the slave sensor
    + *
    + * returns 0 or non-zero error code
    + */
    +static int inv_mpu_config(struct mldl_cfg *mldl_cfg,
    + void *gyro_adapter,
    + struct ext_slave_config __user *usr_config)
    +{
    + int retval = 0;
    + struct ext_slave_config config;
    +
    + retval = copy_from_user(&config, usr_config, sizeof(config));
    + if (retval)
    + return -EFAULT;
    +
    + if (config.len && config.data) {
    + void *data;
    + data = kmalloc(config.len, GFP_KERNEL);
    + if (!data)
    + return -ENOMEM;
    +
    + retval = copy_from_user(data,
    + (void __user *)config.data, config.len);
    + if (retval) {
    + retval = -EFAULT;
    + kfree(data);
    + return retval;
    + }
    + config.data = data;
    + }
    + retval = gyro_config(gyro_adapter, mldl_cfg, &config);
    + kfree(config.data);
    + return retval;
    +}
    +
    +static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
    + void *gyro_adapter,
    + struct ext_slave_config __user *usr_config)
    +{
    + int retval = 0;
    + struct ext_slave_config config;
    + void *user_data;
    +
    + retval = copy_from_user(&config, usr_config, sizeof(config));
    + if (retval)
    + return -EFAULT;
    +
    + user_data = config.data;
    + if (config.len && config.data) {
    + void *data;
    + data = kmalloc(config.len, GFP_KERNEL);
    + if (!data)
    + return -ENOMEM;
    +
    + retval = copy_from_user(data,
    + (void __user *)config.data, config.len);
    + if (retval) {
    + retval = -EFAULT;
    + kfree(data);
    + return retval;
    + }
    + config.data = data;
    + }
    + retval = gyro_get_config(gyro_adapter, mldl_cfg, &config);
    + if (!retval)
    + retval = copy_to_user((unsigned char __user *)user_data,
    + config.data, config.len);
    + kfree(config.data);
    + return retval;
    +}
    +
    +static int slave_config(struct mldl_cfg *mldl_cfg,
    + void *gyro_adapter,
    + void *slave_adapter,
    + struct ext_slave_descr *slave,
    + struct ext_slave_platform_data *pdata,
    + struct ext_slave_config __user *usr_config)
    +{
    + int retval = 0;
    + struct ext_slave_config config;
    + if ((!slave) || (!slave->config))
    + return -ENODEV;
    +
    + retval = copy_from_user(&config, usr_config, sizeof(config));
    + if (retval)
    + return -EFAULT;
    +
    + if (config.len && config.data) {
    + void *data;
    + data = kmalloc(config.len, GFP_KERNEL);
    + if (!data)
    + return -ENOMEM;
    +
    + retval = copy_from_user(data,
    + (void __user *)config.data, config.len);
    + if (retval) {
    + retval = -EFAULT;
    + kfree(data);
    + return retval;
    + }
    + config.data = data;
    + }
    + retval = inv_mpu_slave_config(mldl_cfg, gyro_adapter, slave_adapter,
    + &config, slave, pdata);
    + kfree(config.data);
    + return retval;
    +}
    +
    +static int slave_get_config(struct mldl_cfg *mldl_cfg,
    + void *gyro_adapter,
    + void *slave_adapter,
    + struct ext_slave_descr *slave,
    + struct ext_slave_platform_data *pdata,
    + struct ext_slave_config __user *usr_config)
    +{
    + int retval = 0;
    + struct ext_slave_config config;
    + void *user_data;
    + if (!(slave) || !(slave->get_config))
    + return -ENODEV;
    +
    + retval = copy_from_user(&config, usr_config, sizeof(config));
    + if (retval)
    + return -EFAULT;
    +
    + user_data = config.data;
    + if (config.len && config.data) {
    + void *data;
    + data = kmalloc(config.len, GFP_KERNEL);
    + if (!data)
    + return -ENOMEM;
    +
    + retval = copy_from_user(data,
    + (void __user *)config.data, config.len);
    + if (retval) {
    + retval = -EFAULT;
    + kfree(data);
    + return retval;
    + }
    + config.data = data;
    + }
    + retval = inv_mpu_get_slave_config(mldl_cfg, gyro_adapter,
    + slave_adapter, &config, slave, pdata);
    + if (retval) {
    + kfree(config.data);
    + return retval;
    + }
    + retval = copy_to_user((unsigned char __user *)user_data,
    + config.data, config.len);
    + kfree(config.data);
    + return retval;
    +}
    +
    +static int inv_slave_read(struct mldl_cfg *mldl_cfg,
    + void *gyro_adapter,
    + void *slave_adapter,
    + struct ext_slave_descr *slave,
    + struct ext_slave_platform_data *pdata,
    + void __user *usr_data)
    +{
    + int retval;
    + unsigned char *data;
    + data = kzalloc(slave->read_len, GFP_KERNEL);
    + if (!data)
    + return -EFAULT;
    +
    + retval = inv_mpu_slave_read(mldl_cfg, gyro_adapter, slave_adapter,
    + slave, pdata, data);
    +
    + if ((!retval) &&
    + (copy_to_user((unsigned char __user *)usr_data,
    + data, slave->read_len)))
    + retval = -EFAULT;
    +
    + kfree(data);
    + return retval;
    +}
    +
    +static int mpu_handle_mlsl(void *sl_handle,
    + unsigned char addr,
    + unsigned int cmd,
    + struct mpu_read_write __user *usr_msg)
    +{
    + int retval = 0;
    + struct mpu_read_write msg;
    + unsigned char *user_data;
    + retval = copy_from_user(&msg, usr_msg, sizeof(msg));
    + if (retval)
    + return -EFAULT;
    +
    + user_data = msg.data;
    + if (msg.length && msg.data) {
    + unsigned char *data;
    + data = kmalloc(msg.length, GFP_KERNEL);
    + if (!data)
    + return -ENOMEM;
    +
    + retval = copy_from_user(data,
    + (void __user *)msg.data, msg.length);
    + if (retval) {
    + retval = -EFAULT;
    + kfree(data);
    + return retval;
    + }
    + msg.data = data;
    + } else {
    + return -EPERM;
    + }
    +
    + switch (cmd) {
    + case MPU_READ:
    + retval = inv_serial_read(sl_handle, addr,
    + msg.address, msg.length, msg.data);
    + break;
    + case MPU_WRITE:
    + retval = inv_serial_write(sl_handle, addr,
    + msg.length, msg.data);
    + break;
    + case MPU_READ_MEM:
    + retval = inv_serial_read_mem(sl_handle, addr,
    + msg.address, msg.length, msg.data);
    + break;
    + case MPU_WRITE_MEM:
    + retval = inv_serial_write_mem(sl_handle, addr,
    + msg.address, msg.length,
    + msg.data);
    + break;
    + case MPU_READ_FIFO:
    + retval = inv_serial_read_fifo(sl_handle, addr,
    + msg.length, msg.data);
    + break;
    + case MPU_WRITE_FIFO:
    + retval = inv_serial_write_fifo(sl_handle, addr,
    + msg.length, msg.data);
    + break;
    +
    + };
    + if (retval) {
    + dev_err(&((struct i2c_adapter *)sl_handle)->dev,
    + "%s: i2c %d error %d\n",
    + __func__, cmd, retval);
    + kfree(msg.data);
    + return retval;
    + }
    + retval = copy_to_user((unsigned char __user *)user_data,
    + msg.data, msg.length);
    + kfree(msg.data);
    + return retval;
    +}
    +
    +/* ioctl - I/O control */
    +static long mpu_dev_ioctl(struct file *file,
    + unsigned int cmd, unsigned long arg)
    +{
    + struct mpu_private_data *mpu =
    + container_of(file->private_data, struct mpu_private_data, dev);
    + struct i2c_client *client = mpu->client;
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + int retval = 0;
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct ext_slave_descr **slave = mldl_cfg->slave;
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    + int ii;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    +
    + retval = mutex_lock_interruptible(&mpu->mutex);
    + if (retval) {
    + dev_err(&client->adapter->dev,
    + "%s: mutex_lock_interruptible returned %d\n",
    + __func__, retval);
    + return retval;
    + }
    +
    + switch (cmd) {
    + case MPU_GET_EXT_SLAVE_PLATFORM_DATA:
    + retval = mpu_dev_ioctl_get_ext_slave_platform_data(
    + client,
    + (struct ext_slave_platform_data __user *)arg);
    + break;
    + case MPU_GET_MPU_PLATFORM_DATA:
    + retval = mpu_dev_ioctl_get_mpu_platform_data(
    + client,
    + (struct mpu_platform_data __user *)arg);
    + break;
    + case MPU_GET_EXT_SLAVE_DESCR:
    + retval = mpu_dev_ioctl_get_ext_slave_descr(
    + client,
    + (struct ext_slave_descr __user *)arg);
    + break;
    + case MPU_READ:
    + case MPU_WRITE:
    + case MPU_READ_MEM:
    + case MPU_WRITE_MEM:
    + case MPU_READ_FIFO:
    + case MPU_WRITE_FIFO:
    + retval = mpu_handle_mlsl(
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + mldl_cfg->mpu_chip_info->addr, cmd,
    + (struct mpu_read_write __user *)arg);
    + break;
    + case MPU_CONFIG_GYRO:
    + retval = inv_mpu_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_CONFIG_ACCEL:
    + retval = slave_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave[EXT_SLAVE_TYPE_ACCEL],
    + pdata_slave[EXT_SLAVE_TYPE_ACCEL],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_CONFIG_COMPASS:
    + retval = slave_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave[EXT_SLAVE_TYPE_COMPASS],
    + pdata_slave[EXT_SLAVE_TYPE_COMPASS],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_CONFIG_PRESSURE:
    + retval = slave_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + slave[EXT_SLAVE_TYPE_PRESSURE],
    + pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_GET_CONFIG_GYRO:
    + retval = inv_mpu_get_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_GET_CONFIG_ACCEL:
    + retval = slave_get_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave[EXT_SLAVE_TYPE_ACCEL],
    + pdata_slave[EXT_SLAVE_TYPE_ACCEL],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_GET_CONFIG_COMPASS:
    + retval = slave_get_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave[EXT_SLAVE_TYPE_COMPASS],
    + pdata_slave[EXT_SLAVE_TYPE_COMPASS],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_GET_CONFIG_PRESSURE:
    + retval = slave_get_config(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + slave[EXT_SLAVE_TYPE_PRESSURE],
    + pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
    + (struct ext_slave_config __user *)arg);
    + break;
    + case MPU_SUSPEND:
    + retval = inv_mpu_suspend(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + arg);
    + break;
    + case MPU_RESUME:
    + retval = inv_mpu_resume(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + arg);
    + break;
    + case MPU_PM_EVENT_HANDLED:
    + dev_dbg(&client->adapter->dev, "%s: %d\n", __func__, cmd);
    + complete(&mpu->completion);
    + break;
    + case MPU_READ_ACCEL:
    + retval = inv_slave_read(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave[EXT_SLAVE_TYPE_ACCEL],
    + pdata_slave[EXT_SLAVE_TYPE_ACCEL],
    + (unsigned char __user *)arg);
    + break;
    + case MPU_READ_COMPASS:
    + retval = inv_slave_read(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave[EXT_SLAVE_TYPE_COMPASS],
    + pdata_slave[EXT_SLAVE_TYPE_COMPASS],
    + (unsigned char __user *)arg);
    + break;
    + case MPU_READ_PRESSURE:
    + retval = inv_slave_read(
    + mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + slave[EXT_SLAVE_TYPE_PRESSURE],
    + pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
    + (unsigned char __user *)arg);
    + break;
    + case MPU_GET_REQUESTED_SENSORS:
    + if (copy_to_user(
    + (__u32 __user *)arg,
    + &mldl_cfg->inv_mpu_cfg->requested_sensors,
    + sizeof(mldl_cfg->inv_mpu_cfg->requested_sensors)))
    + retval = -EFAULT;
    + break;
    + case MPU_SET_REQUESTED_SENSORS:
    + mldl_cfg->inv_mpu_cfg->requested_sensors = arg;
    + break;
    + case MPU_GET_IGNORE_SYSTEM_SUSPEND:
    + if (copy_to_user(
    + (unsigned char __user *)arg,
    + &mldl_cfg->inv_mpu_cfg->ignore_system_suspend,
    + sizeof(mldl_cfg->inv_mpu_cfg->ignore_system_suspend)))
    + retval = -EFAULT;
    + break;
    + case MPU_SET_IGNORE_SYSTEM_SUSPEND:
    + mldl_cfg->inv_mpu_cfg->ignore_system_suspend = arg;
    + break;
    + case MPU_GET_MLDL_STATUS:
    + if (copy_to_user(
    + (unsigned char __user *)arg,
    + &mldl_cfg->inv_mpu_state->status,
    + sizeof(mldl_cfg->inv_mpu_state->status)))
    + retval = -EFAULT;
    + break;
    + case MPU_GET_I2C_SLAVES_ENABLED:
    + if (copy_to_user(
    + (unsigned char __user *)arg,
    + &mldl_cfg->inv_mpu_state->i2c_slaves_enabled,
    + sizeof(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)))
    + retval = -EFAULT;
    + break;
    + default:
    + dev_err(&client->adapter->dev,
    + "%s: Unknown cmd %x, arg %lu\n",
    + __func__, cmd, arg);
    + retval = -EINVAL;
    + };
    +
    + mutex_unlock(&mpu->mutex);
    + dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",
    + __func__, cmd, arg, retval);
    +
    + if (retval > 0)
    + retval = -retval;
    +
    + return retval;
    +}
    +
    +void mpu_shutdown(struct i2c_client *client)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    + int ii;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    +
    + mutex_lock(&mpu->mutex);
    + (void)inv_mpu_suspend(mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + INV_ALL_SENSORS);
    + mutex_unlock(&mpu->mutex);
    + dev_dbg(&client->adapter->dev, "%s\n", __func__);
    +}
    +
    +int mpu_dev_suspend(struct i2c_client *client, pm_message_t mesg)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    + int ii;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    +
    + mutex_lock(&mpu->mutex);
    + if (!mldl_cfg->inv_mpu_cfg->ignore_system_suspend) {
    + dev_dbg(&client->adapter->dev,
    + "%s: suspending on event %d\n", __func__, mesg.event);
    + (void)inv_mpu_suspend(mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + INV_ALL_SENSORS);
    + } else {
    + dev_dbg(&client->adapter->dev,
    + "%s: Already suspended %d\n", __func__, mesg.event);
    + }
    + mutex_unlock(&mpu->mutex);
    + return 0;
    +}
    +
    +int mpu_dev_resume(struct i2c_client *client)
    +{
    + struct mpu_private_data *mpu =
    + (struct mpu_private_data *)i2c_get_clientdata(client);
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    + int ii;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    +
    + mutex_lock(&mpu->mutex);
    + if (mpu->pid && !mldl_cfg->inv_mpu_cfg->ignore_system_suspend) {
    + (void)inv_mpu_resume(mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
    + mldl_cfg->inv_mpu_cfg->requested_sensors);
    + dev_dbg(&client->adapter->dev,
    + "%s for pid %d\n", __func__, mpu->pid);
    + }
    + mutex_unlock(&mpu->mutex);
    + return 0;
    +}
    +
    +/* define which file operations are supported */
    +static const struct file_operations mpu_fops = {
    + .owner = THIS_MODULE,
    + .read = mpu_read,
    + .poll = mpu_poll,
    + .unlocked_ioctl = mpu_dev_ioctl,
    + .open = mpu_dev_open,
    + .release = mpu_release,
    +};
    +
    +int inv_mpu_register_slave(struct module *slave_module,
    + struct i2c_client *slave_client,
    + struct ext_slave_platform_data *slave_pdata,
    + struct ext_slave_descr *(*get_slave_descr)(void))
    +{
    + struct mpu_private_data *mpu = mpu_private_data;
    + struct mldl_cfg *mldl_cfg;
    + struct ext_slave_descr *slave_descr;
    + struct ext_slave_platform_data **pdata_slave;
    + char *irq_name;
    + int result = 0;
    +
    + if (!slave_client || !slave_pdata || !get_slave_descr)
    + return -EINVAL;
    +
    + if (!mpu) {
    + dev_err(&slave_client->adapter->dev,
    + "%s: Null mpu_private_data\n", __func__);
    + return -EINVAL;
    + }
    + mldl_cfg = &mpu->mldl_cfg;
    + pdata_slave = mldl_cfg->pdata_slave;
    +
    + slave_descr = get_slave_descr();
    + if (!slave_descr) {
    + dev_err(&slave_client->adapter->dev,
    + "%s: Null ext_slave_descr\n", __func__);
    + return -EINVAL;
    + }
    +
    + mutex_lock(&mpu->mutex);
    + if (mpu->pid) {
    + mutex_unlock(&mpu->mutex);
    + return -EBUSY;
    + }
    +
    + mpu->slave_modules[slave_descr->type] = slave_module;
    +
    + if (pdata_slave[slave_descr->type]) {
    + result = -EBUSY;
    + goto out_unlock_mutex;
    + }
    +
    + pdata_slave[slave_descr->type] = slave_pdata;
    + pdata_slave[slave_descr->type]->address = slave_client->addr;
    + pdata_slave[slave_descr->type]->irq = slave_client->irq;
    + pdata_slave[slave_descr->type]->adapt_num =
    + i2c_adapter_id(slave_client->adapter);
    +
    + switch (slave_descr->type) {
    + case EXT_SLAVE_TYPE_ACCEL:
    + irq_name = "accelirq";
    + break;
    + case EXT_SLAVE_TYPE_COMPASS:
    + irq_name = "compassirq";
    + break;
    + case EXT_SLAVE_TYPE_PRESSURE:
    + irq_name = "pressureirq";
    + break;
    + default:
    + irq_name = "none";
    + };
    +
    + if (pdata_slave[slave_descr->type]->irq > 0) {
    + dev_info(&slave_client->adapter->dev,
    + "Installing %s irq using %d\n",
    + irq_name,
    + pdata_slave[slave_descr->type]->irq);
    + result = slaveirq_init(slave_client->adapter,
    + pdata_slave[slave_descr->type], irq_name);
    + if (result)
    + goto out_unlock_mutex;
    + } else {
    + dev_WARN(&slave_client->adapter->dev,
    + "Accel irq not assigned\n");
    + }
    +
    + if (slave_descr->init) {
    + result = slave_descr->init(slave_client->adapter,
    + slave_descr,
    + pdata_slave[slave_descr->type]);
    + if (result) {
    + dev_err(&slave_client->adapter->dev,
    + "Accel init failed %d\n", result);
    + goto out_slaveirq_exit;
    + }
    + }
    +
    + mldl_cfg->slave[slave_descr->type] = slave_descr;
    +
    + dev_info(&slave_client->adapter->dev,
    + "%s: +%s Type %d: Addr: %2x IRQ: %2d, Adapt: %2d\n",
    + __func__,
    + mldl_cfg->slave[slave_descr->type]->name,
    + slave_descr->type,
    + pdata_slave[slave_descr->type]->address,
    + pdata_slave[slave_descr->type]->irq,
    + pdata_slave[slave_descr->type]->adapt_num);
    + goto out_unlock_mutex;
    +
    +out_slaveirq_exit:
    + if (pdata_slave[slave_descr->type]->irq > 0)
    + slaveirq_exit(pdata_slave[slave_descr->type]);
    +out_unlock_mutex:
    + mutex_unlock(&mpu->mutex);
    + return result;
    +}
    +EXPORT_SYMBOL(inv_mpu_register_slave);
    +
    +void inv_mpu_unregister_slave(struct i2c_client *slave_client,
    + struct ext_slave_platform_data *slave_pdata,
    + struct ext_slave_descr *(*get_slave_descr)(void))
    +{
    + struct mpu_private_data *mpu = mpu_private_data;
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + struct ext_slave_descr *slave_descr;
    + int result;
    +
    + dev_info(&slave_client->adapter->dev, "%s\n", __func__);
    +
    + if (!slave_client || !slave_pdata || !get_slave_descr)
    + return;
    +
    + slave_descr = get_slave_descr();
    + if (!slave_descr)
    + return;
    +
    + mutex_lock(&mpu->mutex);
    +
    + if (slave_descr->exit) {
    + result = slave_descr->exit(slave_client->adapter,
    + slave_descr,
    + slave_pdata);
    + if (result)
    + dev_err(&slave_client->adapter->dev,
    + "Accel exit failed %d\n", result);
    + }
    +
    + if (slave_pdata->irq)
    + slaveirq_exit(slave_pdata);
    +
    + mldl_cfg->slave[slave_descr->type] = NULL;
    + mldl_cfg->pdata_slave[slave_descr->type] = NULL;
    + mpu->slave_modules[slave_descr->type] = NULL;
    +
    + mutex_unlock(&mpu->mutex);
    +}
    +EXPORT_SYMBOL(inv_mpu_unregister_slave);
    +
    +static unsigned short normal_i2c[] = { I2C_CLIENT_END };
    +
    +static const struct i2c_device_id mpu_id[] = {
    + {"mpu3050", 0},
    + {"mpu6050", 0},
    + {"mpu6050_no_accel", 0},
    + {}
    +};
    +MODULE_DEVICE_TABLE(i2c, mpu_id);
    +
    +int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
    +{
    + struct mpu_platform_data *pdata;
    + struct mpu_private_data *mpu;
    + struct mldl_cfg *mldl_cfg;
    + int res = 0;
    + int ii = 0;
    +
    + dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++);
    +
    + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    + res = -ENODEV;
    + goto out_check_functionality_failed;
    + }
    +
    + mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL);
    + if (!mpu) {
    + res = -ENOMEM;
    + goto out_alloc_data_failed;
    + }
    + mldl_cfg = &mpu->mldl_cfg;
    + mldl_cfg->mpu_ram = &mpu->mpu_ram;
    + mldl_cfg->mpu_gyro_cfg = &mpu->mpu_gyro_cfg;
    + mldl_cfg->mpu_offsets = &mpu->mpu_offsets;
    + mldl_cfg->mpu_chip_info = &mpu->mpu_chip_info;
    + mldl_cfg->inv_mpu_cfg = &mpu->inv_mpu_cfg;
    + mldl_cfg->inv_mpu_state = &mpu->inv_mpu_state;
    +
    + mldl_cfg->mpu_ram->length = MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE;
    + mldl_cfg->mpu_ram->ram = kzalloc(mldl_cfg->mpu_ram->length, GFP_KERNEL);
    + if (!mldl_cfg->mpu_ram->ram) {
    + res = -ENOMEM;
    + goto out_alloc_ram_failed;
    + }
    + mpu_private_data = mpu;
    + i2c_set_clientdata(client, mpu);
    + mpu->client = client;
    +
    + init_waitqueue_head(&mpu->mpu_event_wait);
    + mutex_init(&mpu->mutex);
    + init_completion(&mpu->completion);
    +
    + mpu->response_timeout = 60; /* Seconds */
    + mpu->timeout.function = mpu_pm_timeout;
    + mpu->timeout.data = (u_long) mpu;
    + init_timer(&mpu->timeout);
    +
    + mpu->nb.notifier_call = mpu_pm_notifier_callback;
    + mpu->nb.priority = 0;
    + res = register_pm_notifier(&mpu->nb);
    + if (res) {
    + dev_err(&client->adapter->dev,
    + "Unable to register pm_notifier %d\n", res);
    + goto out_register_pm_notifier_failed;
    + }
    +
    + pdata = (struct mpu_platform_data *)client->dev.platform_data;
    + if (!pdata) {
    + dev_WARN(&client->adapter->dev,
    + "Missing platform data for mpu\n");
    + }
    + mldl_cfg->pdata = pdata;
    +
    + mldl_cfg->mpu_chip_info->addr = client->addr;
    + res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
    +
    + if (res) {
    + dev_err(&client->adapter->dev,
    + "Unable to open %s %d\n", MPU_NAME, res);
    + res = -ENODEV;
    + goto out_whoami_failed;
    + }
    +
    + mpu->dev.minor = MISC_DYNAMIC_MINOR;
    + mpu->dev.name = "mpu";
    + mpu->dev.fops = &mpu_fops;
    + res = misc_register(&mpu->dev);
    + if (res < 0) {
    + dev_err(&client->adapter->dev,
    + "ERROR: misc_register returned %d\n", res);
    + goto out_misc_register_failed;
    + }
    +
    + if (client->irq) {
    + dev_info(&client->adapter->dev,
    + "Installing irq using %d\n", client->irq);
    + res = mpuirq_init(client, mldl_cfg);
    + if (res)
    + goto out_mpuirq_failed;
    + } else {
    + dev_WARN(&client->adapter->dev,
    + "Missing %s IRQ\n", MPU_NAME);
    + }
    +
    + return res;
    +
    +out_mpuirq_failed:
    + misc_deregister(&mpu->dev);
    +out_misc_register_failed:
    + inv_mpu_close(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
    +out_whoami_failed:
    + unregister_pm_notifier(&mpu->nb);
    +out_register_pm_notifier_failed:
    + kfree(mldl_cfg->mpu_ram->ram);
    + mpu_private_data = NULL;
    +out_alloc_ram_failed:
    + kfree(mpu);
    +out_alloc_data_failed:
    +out_check_functionality_failed:
    + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, res);
    + return res;
    +
    +}
    +
    +static int mpu_remove(struct i2c_client *client)
    +{
    + struct mpu_private_data *mpu = i2c_get_clientdata(client);
    + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
    + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
    + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
    + int ii;
    +
    + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
    + if (!pdata_slave[ii])
    + slave_adapter[ii] = NULL;
    + else
    + slave_adapter[ii] =
    + i2c_get_adapter(pdata_slave[ii]->adapt_num);
    + }
    +
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
    + dev_dbg(&client->adapter->dev, "%s\n", __func__);
    +
    + inv_mpu_close(mldl_cfg,
    + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
    + slave_adapter[EXT_SLAVE_TYPE_ACCEL],
    + slave_adapter[EXT_SLAVE_TYPE_COMPASS],
    + slave_adapter[EXT_SLAVE_TYPE_PRESSURE]);
    +
    + if (client->irq)
    + mpuirq_exit();
    +
    + for (ii = EXT_SLAVE_TYPE_ACCEL - 1; ii >= 0; ii--) {
    + if (pdata_slave[ii] &&
    + pdata_slave[ii]->irq) {
    + slaveirq_exit(pdata_slave[ii]);
    + }
    + }
    +
    + unregister_pm_notifier(&mpu->nb);
    +
    + misc_deregister(&mpu->dev);
    + kfree(mpu);
    +
    + return 0;
    +}
    +
    +static struct i2c_driver mpu_driver = {
    + .class = I2C_CLASS_HWMON,
    + .probe = mpu_probe,
    + .remove = mpu_remove,
    + .id_table = mpu_id,
    + .driver = {
    + .owner = THIS_MODULE,
    + .name = MPU_NAME,
    + },
    + .address_list = normal_i2c,
    + .shutdown = mpu_shutdown, /* optional */
    + .suspend = mpu_dev_suspend, /* optional */
    + .resume = mpu_dev_resume, /* optional */
    +
    +};
    +
    +static int __init mpu_init(void)
    +{
    + int res = i2c_add_driver(&mpu_driver);
    + pr_info("%s: Probe name %s\n", __func__, MPU_NAME);
    + if (res)
    + pr_err("%s failed\n", __func__);
    + return res;
    +}
    +
    +static void __exit mpu_exit(void)
    +{
    + pr_info("%s\n", __func__);
    + i2c_del_driver(&mpu_driver);
    +}
    +
    +module_init(mpu_init);
    +module_exit(mpu_exit);
    +
    +MODULE_AUTHOR("Invensense Corporation");
    +MODULE_DESCRIPTION("User space character device interface for MPU");
    +MODULE_LICENSE("GPL");
    +MODULE_ALIAS(MPU_NAME);
    diff --git a/drivers/misc/inv_mpu/mpu-dev.h b/drivers/misc/inv_mpu/mpu-dev.h
    new file mode 100644
    index 0000000..b6a4fcf
    --- /dev/null
    +++ b/drivers/misc/inv_mpu/mpu-dev.h
    @@ -0,0 +1,36 @@
    +/*
    + $License:
    + Copyright (C) 2011 InvenSense Corporation, 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, see <http://www.gnu.org/licenses/>.
    + $
    + */
    +
    +
    +#ifndef __MPU_DEV_H__
    +#define __MPU_DEV_H__
    +
    +#include <linux/i2c.h>
    +#include <linux/module.h>
    +#include <linux/mpu.h>
    +
    +int inv_mpu_register_slave(struct module *slave_module,
    + struct i2c_client *client,
    + struct ext_slave_platform_data *pdata,
    + struct ext_slave_descr *(*slave_descr)(void));
    +
    +void inv_mpu_unregister_slave(struct i2c_client *client,
    + struct ext_slave_platform_data *pdata,
    + struct ext_slave_descr *(*slave_descr)(void));
    +#endif
    --
    1.7.4.1


    \
     
     \ /
      Last update: 2011-07-01 04:23    [W:0.091 / U:32.852 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site