aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/inv_mpu/mpu3050/mpu-dev.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/inv_mpu/mpu3050/mpu-dev.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/inv_mpu/mpu3050/mpu-dev.c')
-rw-r--r--drivers/misc/inv_mpu/mpu3050/mpu-dev.c1250
1 files changed, 1250 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/mpu3050/mpu-dev.c b/drivers/misc/inv_mpu/mpu3050/mpu-dev.c
new file mode 100644
index 00000000000..c98ed3b4a80
--- /dev/null
+++ b/drivers/misc/inv_mpu/mpu3050/mpu-dev.c
@@ -0,0 +1,1250 @@
1/*
2 $License:
3 Copyright (C) 2011 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/i2c.h>
20#include <linux/i2c-dev.h>
21#include <linux/interrupt.h>
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/stat.h>
27#include <linux/irq.h>
28#include <linux/gpio.h>
29#include <linux/signal.h>
30#include <linux/miscdevice.h>
31#include <linux/slab.h>
32#include <linux/version.h>
33#include <linux/pm.h>
34#include <linux/mutex.h>
35#include <linux/suspend.h>
36#include <linux/poll.h>
37
38#include <linux/errno.h>
39#include <linux/fs.h>
40#include <linux/mm.h>
41#include <linux/sched.h>
42#include <linux/wait.h>
43#include <linux/uaccess.h>
44#include <linux/io.h>
45
46#include "mpuirq.h"
47#include "slaveirq.h"
48#include "mlsl.h"
49#include "mldl_cfg.h"
50#include <linux/mpu.h>
51
52
53/* Platform data for the MPU */
54struct mpu_private_data {
55 struct miscdevice dev;
56 struct i2c_client *client;
57
58 /* mldl_cfg data */
59 struct mldl_cfg mldl_cfg;
60 struct mpu_ram mpu_ram;
61 struct mpu_gyro_cfg mpu_gyro_cfg;
62 struct mpu_offsets mpu_offsets;
63 struct mpu_chip_info mpu_chip_info;
64 struct inv_mpu_cfg inv_mpu_cfg;
65 struct inv_mpu_state inv_mpu_state;
66
67 struct mutex mutex;
68 wait_queue_head_t mpu_event_wait;
69 struct completion completion;
70 struct timer_list timeout;
71 struct notifier_block nb;
72 struct mpuirq_data mpu_pm_event;
73 int response_timeout; /* In seconds */
74 unsigned long event;
75 int pid;
76 struct module *slave_modules[EXT_SLAVE_NUM_TYPES];
77};
78
79struct mpu_private_data *mpu_private_data;
80
81static void mpu_pm_timeout(u_long data)
82{
83 struct mpu_private_data *mpu = (struct mpu_private_data *)data;
84 struct i2c_client *client = mpu->client;
85 dev_dbg(&client->adapter->dev, "%s\n", __func__);
86 complete(&mpu->completion);
87}
88
89static int mpu_pm_notifier_callback(struct notifier_block *nb,
90 unsigned long event, void *unused)
91{
92 struct mpu_private_data *mpu =
93 container_of(nb, struct mpu_private_data, nb);
94 struct i2c_client *client = mpu->client;
95 struct timeval event_time;
96 dev_dbg(&client->adapter->dev, "%s: %ld\n", __func__, event);
97
98 /* Prevent the file handle from being closed before we initialize
99 the completion event */
100 mutex_lock(&mpu->mutex);
101 if (!(mpu->pid) ||
102 (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) {
103 mutex_unlock(&mpu->mutex);
104 return NOTIFY_OK;
105 }
106
107 if (event == PM_SUSPEND_PREPARE)
108 mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE;
109 if (event == PM_POST_SUSPEND)
110 mpu->event = MPU_PM_EVENT_POST_SUSPEND;
111
112 do_gettimeofday(&event_time);
113 mpu->mpu_pm_event.interruptcount++;
114 mpu->mpu_pm_event.irqtime =
115 (((long long)event_time.tv_sec) << 32) + event_time.tv_usec;
116 mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT;
117 mpu->mpu_pm_event.data = mpu->event;
118
119 if (mpu->response_timeout > 0) {
120 mpu->timeout.expires = jiffies + mpu->response_timeout * HZ;
121 add_timer(&mpu->timeout);
122 }
123 INIT_COMPLETION(mpu->completion);
124 mutex_unlock(&mpu->mutex);
125
126 wake_up_interruptible(&mpu->mpu_event_wait);
127 wait_for_completion(&mpu->completion);
128 del_timer_sync(&mpu->timeout);
129 dev_dbg(&client->adapter->dev, "%s: %ld DONE\n", __func__, event);
130 return NOTIFY_OK;
131}
132
133static int mpu_dev_open(struct inode *inode, struct file *file)
134{
135 struct mpu_private_data *mpu =
136 container_of(file->private_data, struct mpu_private_data, dev);
137 struct i2c_client *client = mpu->client;
138 int result;
139 int ii;
140 dev_dbg(&client->adapter->dev, "%s\n", __func__);
141 dev_dbg(&client->adapter->dev, "current->pid %d\n", current->pid);
142
143 result = mutex_lock_interruptible(&mpu->mutex);
144 if (mpu->pid) {
145 mutex_unlock(&mpu->mutex);
146 return -EBUSY;
147 }
148 mpu->pid = current->pid;
149
150 /* Reset the sensors to the default */
151 if (result) {
152 dev_err(&client->adapter->dev,
153 "%s: mutex_lock_interruptible returned %d\n",
154 __func__, result);
155 return result;
156 }
157
158 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++)
159 __module_get(mpu->slave_modules[ii]);
160
161 mutex_unlock(&mpu->mutex);
162 return 0;
163}
164
165/* close function - called when the "file" /dev/mpu is closed in userspace */
166static int mpu_release(struct inode *inode, struct file *file)
167{
168 struct mpu_private_data *mpu =
169 container_of(file->private_data, struct mpu_private_data, dev);
170 struct i2c_client *client = mpu->client;
171 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
172 int result = 0;
173 int ii;
174 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
175 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
176
177 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
178 if (!pdata_slave[ii])
179 slave_adapter[ii] = NULL;
180 else
181 slave_adapter[ii] =
182 i2c_get_adapter(pdata_slave[ii]->adapt_num);
183 }
184 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
185
186 mutex_lock(&mpu->mutex);
187 mldl_cfg->inv_mpu_cfg->requested_sensors = 0;
188 result = inv_mpu_suspend(mldl_cfg,
189 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
190 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
191 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
192 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
193 INV_ALL_SENSORS);
194 mpu->pid = 0;
195 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++)
196 module_put(mpu->slave_modules[ii]);
197
198 mutex_unlock(&mpu->mutex);
199 complete(&mpu->completion);
200 dev_dbg(&client->adapter->dev, "mpu_release\n");
201
202 return result;
203}
204
205/* read function called when from /dev/mpu is read. Read from the FIFO */
206static ssize_t mpu_read(struct file *file,
207 char __user *buf, size_t count, loff_t *offset)
208{
209 struct mpu_private_data *mpu =
210 container_of(file->private_data, struct mpu_private_data, dev);
211 struct i2c_client *client = mpu->client;
212 size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long);
213 int err;
214
215 if (!mpu->event && (!(file->f_flags & O_NONBLOCK)))
216 wait_event_interruptible(mpu->mpu_event_wait, mpu->event);
217
218 if (!mpu->event || !buf
219 || count < sizeof(mpu->mpu_pm_event))
220 return 0;
221
222 err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event));
223 if (err) {
224 dev_err(&client->adapter->dev,
225 "Copy to user returned %d\n", err);
226 return -EFAULT;
227 }
228 mpu->event = 0;
229 return len;
230}
231
232static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll)
233{
234 struct mpu_private_data *mpu =
235 container_of(file->private_data, struct mpu_private_data, dev);
236 int mask = 0;
237
238 poll_wait(file, &mpu->mpu_event_wait, poll);
239 if (mpu->event)
240 mask |= POLLIN | POLLRDNORM;
241 return mask;
242}
243
244static int mpu_dev_ioctl_get_ext_slave_platform_data(
245 struct i2c_client *client,
246 struct ext_slave_platform_data __user *arg)
247{
248 struct mpu_private_data *mpu =
249 (struct mpu_private_data *)i2c_get_clientdata(client);
250 struct ext_slave_platform_data *pdata_slave;
251 struct ext_slave_platform_data local_pdata_slave;
252
253 if (copy_from_user(&local_pdata_slave, arg, sizeof(local_pdata_slave)))
254 return -EFAULT;
255
256 if (local_pdata_slave.type >= EXT_SLAVE_NUM_TYPES)
257 return -EINVAL;
258
259 pdata_slave = mpu->mldl_cfg.pdata_slave[local_pdata_slave.type];
260 /* All but private data and irq_data */
261 if (!pdata_slave)
262 return -ENODEV;
263 if (copy_to_user(arg, pdata_slave, sizeof(*pdata_slave)))
264 return -EFAULT;
265 return 0;
266}
267
268static int mpu_dev_ioctl_get_mpu_platform_data(
269 struct i2c_client *client,
270 struct mpu_platform_data __user *arg)
271{
272 struct mpu_private_data *mpu =
273 (struct mpu_private_data *)i2c_get_clientdata(client);
274 struct mpu_platform_data *pdata = mpu->mldl_cfg.pdata;
275
276 if (copy_to_user(arg, pdata, sizeof(*pdata)))
277 return -EFAULT;
278 return 0;
279}
280
281static int mpu_dev_ioctl_get_ext_slave_descr(
282 struct i2c_client *client,
283 struct ext_slave_descr __user *arg)
284{
285 struct mpu_private_data *mpu =
286 (struct mpu_private_data *)i2c_get_clientdata(client);
287 struct ext_slave_descr *slave;
288 struct ext_slave_descr local_slave;
289
290 if (copy_from_user(&local_slave, arg, sizeof(local_slave)))
291 return -EFAULT;
292
293 if (local_slave.type >= EXT_SLAVE_NUM_TYPES)
294 return -EINVAL;
295
296 slave = mpu->mldl_cfg.slave[local_slave.type];
297 /* All but private data and irq_data */
298 if (!slave)
299 return -ENODEV;
300 if (copy_to_user(arg, slave, sizeof(*slave)))
301 return -EFAULT;
302 return 0;
303}
304
305
306/**
307 * slave_config() - Pass a requested slave configuration to the slave sensor
308 *
309 * @adapter the adaptor to use to communicate with the slave
310 * @mldl_cfg the mldl configuration structuer
311 * @slave pointer to the slave descriptor
312 * @usr_config The configuration to pass to the slave sensor
313 *
314 * returns 0 or non-zero error code
315 */
316static int inv_mpu_config(struct mldl_cfg *mldl_cfg,
317 void *gyro_adapter,
318 struct ext_slave_config __user *usr_config)
319{
320 int retval = 0;
321 struct ext_slave_config config;
322
323 retval = copy_from_user(&config, usr_config, sizeof(config));
324 if (retval)
325 return -EFAULT;
326
327 if (config.len && config.data) {
328 void *data;
329 data = kmalloc(config.len, GFP_KERNEL);
330 if (!data)
331 return -ENOMEM;
332
333 retval = copy_from_user(data,
334 (void __user *)config.data, config.len);
335 if (retval) {
336 retval = -EFAULT;
337 kfree(data);
338 return retval;
339 }
340 config.data = data;
341 }
342 retval = gyro_config(gyro_adapter, mldl_cfg, &config);
343 kfree(config.data);
344 return retval;
345}
346
347static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
348 void *gyro_adapter,
349 struct ext_slave_config __user *usr_config)
350{
351 int retval = 0;
352 struct ext_slave_config config;
353 void *user_data;
354
355 retval = copy_from_user(&config, usr_config, sizeof(config));
356 if (retval)
357 return -EFAULT;
358
359 user_data = config.data;
360 if (config.len && config.data) {
361 void *data;
362 data = kmalloc(config.len, GFP_KERNEL);
363 if (!data)
364 return -ENOMEM;
365
366 retval = copy_from_user(data,
367 (void __user *)config.data, config.len);
368 if (retval) {
369 retval = -EFAULT;
370 kfree(data);
371 return retval;
372 }
373 config.data = data;
374 }
375 retval = gyro_get_config(gyro_adapter, mldl_cfg, &config);
376 if (!retval)
377 retval = copy_to_user((unsigned char __user *)user_data,
378 config.data, config.len);
379 kfree(config.data);
380 return retval;
381}
382
383static int slave_config(struct mldl_cfg *mldl_cfg,
384 void *gyro_adapter,
385 void *slave_adapter,
386 struct ext_slave_descr *slave,
387 struct ext_slave_platform_data *pdata,
388 struct ext_slave_config __user *usr_config)
389{
390 int retval = 0;
391 struct ext_slave_config config;
392 if ((!slave) || (!slave->config))
393 return -ENODEV;
394
395 retval = copy_from_user(&config, usr_config, sizeof(config));
396 if (retval)
397 return -EFAULT;
398
399 if (config.len && config.data) {
400 void *data;
401 data = kmalloc(config.len, GFP_KERNEL);
402 if (!data)
403 return -ENOMEM;
404
405 retval = copy_from_user(data,
406 (void __user *)config.data, config.len);
407 if (retval) {
408 retval = -EFAULT;
409 kfree(data);
410 return retval;
411 }
412 config.data = data;
413 }
414 retval = inv_mpu_slave_config(mldl_cfg, gyro_adapter, slave_adapter,
415 &config, slave, pdata);
416 kfree(config.data);
417 return retval;
418}
419
420static int slave_get_config(struct mldl_cfg *mldl_cfg,
421 void *gyro_adapter,
422 void *slave_adapter,
423 struct ext_slave_descr *slave,
424 struct ext_slave_platform_data *pdata,
425 struct ext_slave_config __user *usr_config)
426{
427 int retval = 0;
428 struct ext_slave_config config;
429 void *user_data;
430 if (!(slave) || !(slave->get_config))
431 return -ENODEV;
432
433 retval = copy_from_user(&config, usr_config, sizeof(config));
434 if (retval)
435 return -EFAULT;
436
437 user_data = config.data;
438 if (config.len && config.data) {
439 void *data;
440 data = kmalloc(config.len, GFP_KERNEL);
441 if (!data)
442 return -ENOMEM;
443
444 retval = copy_from_user(data,
445 (void __user *)config.data, config.len);
446 if (retval) {
447 retval = -EFAULT;
448 kfree(data);
449 return retval;
450 }
451 config.data = data;
452 }
453 retval = inv_mpu_get_slave_config(mldl_cfg, gyro_adapter,
454 slave_adapter, &config, slave, pdata);
455 if (retval) {
456 kfree(config.data);
457 return retval;
458 }
459 retval = copy_to_user((unsigned char __user *)user_data,
460 config.data, config.len);
461 kfree(config.data);
462 return retval;
463}
464
465static int inv_slave_read(struct mldl_cfg *mldl_cfg,
466 void *gyro_adapter,
467 void *slave_adapter,
468 struct ext_slave_descr *slave,
469 struct ext_slave_platform_data *pdata,
470 void __user *usr_data)
471{
472 int retval;
473 unsigned char *data;
474 data = kzalloc(slave->read_len, GFP_KERNEL);
475 if (!data)
476 return -EFAULT;
477
478 retval = inv_mpu_slave_read(mldl_cfg, gyro_adapter, slave_adapter,
479 slave, pdata, data);
480
481 if ((!retval) &&
482 (copy_to_user((unsigned char __user *)usr_data,
483 data, slave->read_len)))
484 retval = -EFAULT;
485
486 kfree(data);
487 return retval;
488}
489
490static int mpu_handle_mlsl(void *sl_handle,
491 unsigned char addr,
492 unsigned int cmd,
493 struct mpu_read_write __user *usr_msg)
494{
495 int retval = 0;
496 struct mpu_read_write msg;
497 unsigned char *user_data;
498 retval = copy_from_user(&msg, usr_msg, sizeof(msg));
499 if (retval)
500 return -EFAULT;
501
502 user_data = msg.data;
503 if (msg.length && msg.data) {
504 unsigned char *data;
505 data = kmalloc(msg.length, GFP_KERNEL);
506 if (!data)
507 return -ENOMEM;
508
509 retval = copy_from_user(data,
510 (void __user *)msg.data, msg.length);
511 if (retval) {
512 retval = -EFAULT;
513 kfree(data);
514 return retval;
515 }
516 msg.data = data;
517 } else {
518 return -EPERM;
519 }
520
521 switch (cmd) {
522 case MPU_READ:
523 retval = inv_serial_read(sl_handle, addr,
524 msg.address, msg.length, msg.data);
525 break;
526 case MPU_WRITE:
527 retval = inv_serial_write(sl_handle, addr,
528 msg.length, msg.data);
529 break;
530 case MPU_READ_MEM:
531 retval = inv_serial_read_mem(sl_handle, addr,
532 msg.address, msg.length, msg.data);
533 break;
534 case MPU_WRITE_MEM:
535 retval = inv_serial_write_mem(sl_handle, addr,
536 msg.address, msg.length,
537 msg.data);
538 break;
539 case MPU_READ_FIFO:
540 retval = inv_serial_read_fifo(sl_handle, addr,
541 msg.length, msg.data);
542 break;
543 case MPU_WRITE_FIFO:
544 retval = inv_serial_write_fifo(sl_handle, addr,
545 msg.length, msg.data);
546 break;
547
548 };
549 if (retval) {
550 dev_err(&((struct i2c_adapter *)sl_handle)->dev,
551 "%s: i2c %d error %d\n",
552 __func__, cmd, retval);
553 kfree(msg.data);
554 return retval;
555 }
556 retval = copy_to_user((unsigned char __user *)user_data,
557 msg.data, msg.length);
558 kfree(msg.data);
559 return retval;
560}
561
562/* ioctl - I/O control */
563static long mpu_dev_ioctl(struct file *file,
564 unsigned int cmd, unsigned long arg)
565{
566 struct mpu_private_data *mpu =
567 container_of(file->private_data, struct mpu_private_data, dev);
568 struct i2c_client *client = mpu->client;
569 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
570 int retval = 0;
571 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
572 struct ext_slave_descr **slave = mldl_cfg->slave;
573 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
574 int ii;
575
576 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
577 if (!pdata_slave[ii])
578 slave_adapter[ii] = NULL;
579 else
580 slave_adapter[ii] =
581 i2c_get_adapter(pdata_slave[ii]->adapt_num);
582 }
583 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
584
585 retval = mutex_lock_interruptible(&mpu->mutex);
586 if (retval) {
587 dev_err(&client->adapter->dev,
588 "%s: mutex_lock_interruptible returned %d\n",
589 __func__, retval);
590 return retval;
591 }
592
593 switch (cmd) {
594 case MPU_GET_EXT_SLAVE_PLATFORM_DATA:
595 retval = mpu_dev_ioctl_get_ext_slave_platform_data(
596 client,
597 (struct ext_slave_platform_data __user *)arg);
598 break;
599 case MPU_GET_MPU_PLATFORM_DATA:
600 retval = mpu_dev_ioctl_get_mpu_platform_data(
601 client,
602 (struct mpu_platform_data __user *)arg);
603 break;
604 case MPU_GET_EXT_SLAVE_DESCR:
605 retval = mpu_dev_ioctl_get_ext_slave_descr(
606 client,
607 (struct ext_slave_descr __user *)arg);
608 break;
609 case MPU_READ:
610 case MPU_WRITE:
611 case MPU_READ_MEM:
612 case MPU_WRITE_MEM:
613 case MPU_READ_FIFO:
614 case MPU_WRITE_FIFO:
615 retval = mpu_handle_mlsl(
616 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
617 mldl_cfg->mpu_chip_info->addr, cmd,
618 (struct mpu_read_write __user *)arg);
619 break;
620 case MPU_CONFIG_GYRO:
621 retval = inv_mpu_config(
622 mldl_cfg,
623 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
624 (struct ext_slave_config __user *)arg);
625 break;
626 case MPU_CONFIG_ACCEL:
627 retval = slave_config(
628 mldl_cfg,
629 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
630 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
631 slave[EXT_SLAVE_TYPE_ACCEL],
632 pdata_slave[EXT_SLAVE_TYPE_ACCEL],
633 (struct ext_slave_config __user *)arg);
634 break;
635 case MPU_CONFIG_COMPASS:
636 retval = slave_config(
637 mldl_cfg,
638 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
639 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
640 slave[EXT_SLAVE_TYPE_COMPASS],
641 pdata_slave[EXT_SLAVE_TYPE_COMPASS],
642 (struct ext_slave_config __user *)arg);
643 break;
644 case MPU_CONFIG_PRESSURE:
645 retval = slave_config(
646 mldl_cfg,
647 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
648 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
649 slave[EXT_SLAVE_TYPE_PRESSURE],
650 pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
651 (struct ext_slave_config __user *)arg);
652 break;
653 case MPU_GET_CONFIG_GYRO:
654 retval = inv_mpu_get_config(
655 mldl_cfg,
656 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
657 (struct ext_slave_config __user *)arg);
658 break;
659 case MPU_GET_CONFIG_ACCEL:
660 retval = slave_get_config(
661 mldl_cfg,
662 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
663 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
664 slave[EXT_SLAVE_TYPE_ACCEL],
665 pdata_slave[EXT_SLAVE_TYPE_ACCEL],
666 (struct ext_slave_config __user *)arg);
667 break;
668 case MPU_GET_CONFIG_COMPASS:
669 retval = slave_get_config(
670 mldl_cfg,
671 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
672 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
673 slave[EXT_SLAVE_TYPE_COMPASS],
674 pdata_slave[EXT_SLAVE_TYPE_COMPASS],
675 (struct ext_slave_config __user *)arg);
676 break;
677 case MPU_GET_CONFIG_PRESSURE:
678 retval = slave_get_config(
679 mldl_cfg,
680 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
681 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
682 slave[EXT_SLAVE_TYPE_PRESSURE],
683 pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
684 (struct ext_slave_config __user *)arg);
685 break;
686 case MPU_SUSPEND:
687 retval = inv_mpu_suspend(
688 mldl_cfg,
689 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
690 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
691 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
692 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
693 arg);
694 break;
695 case MPU_RESUME:
696 retval = inv_mpu_resume(
697 mldl_cfg,
698 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
699 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
700 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
701 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
702 arg);
703 break;
704 case MPU_PM_EVENT_HANDLED:
705 dev_dbg(&client->adapter->dev, "%s: %d\n", __func__, cmd);
706 complete(&mpu->completion);
707 break;
708 case MPU_READ_ACCEL:
709 retval = inv_slave_read(
710 mldl_cfg,
711 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
712 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
713 slave[EXT_SLAVE_TYPE_ACCEL],
714 pdata_slave[EXT_SLAVE_TYPE_ACCEL],
715 (unsigned char __user *)arg);
716 break;
717 case MPU_READ_COMPASS:
718 retval = inv_slave_read(
719 mldl_cfg,
720 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
721 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
722 slave[EXT_SLAVE_TYPE_COMPASS],
723 pdata_slave[EXT_SLAVE_TYPE_COMPASS],
724 (unsigned char __user *)arg);
725 break;
726 case MPU_READ_PRESSURE:
727 retval = inv_slave_read(
728 mldl_cfg,
729 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
730 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
731 slave[EXT_SLAVE_TYPE_PRESSURE],
732 pdata_slave[EXT_SLAVE_TYPE_PRESSURE],
733 (unsigned char __user *)arg);
734 break;
735 case MPU_GET_REQUESTED_SENSORS:
736 if (copy_to_user(
737 (__u32 __user *)arg,
738 &mldl_cfg->inv_mpu_cfg->requested_sensors,
739 sizeof(mldl_cfg->inv_mpu_cfg->requested_sensors)))
740 retval = -EFAULT;
741 break;
742 case MPU_SET_REQUESTED_SENSORS:
743 mldl_cfg->inv_mpu_cfg->requested_sensors = arg;
744 break;
745 case MPU_GET_IGNORE_SYSTEM_SUSPEND:
746 if (copy_to_user(
747 (unsigned char __user *)arg,
748 &mldl_cfg->inv_mpu_cfg->ignore_system_suspend,
749 sizeof(mldl_cfg->inv_mpu_cfg->ignore_system_suspend)))
750 retval = -EFAULT;
751 break;
752 case MPU_SET_IGNORE_SYSTEM_SUSPEND:
753 mldl_cfg->inv_mpu_cfg->ignore_system_suspend = arg;
754 break;
755 case MPU_GET_MLDL_STATUS:
756 if (copy_to_user(
757 (unsigned char __user *)arg,
758 &mldl_cfg->inv_mpu_state->status,
759 sizeof(mldl_cfg->inv_mpu_state->status)))
760 retval = -EFAULT;
761 break;
762 case MPU_GET_I2C_SLAVES_ENABLED:
763 if (copy_to_user(
764 (unsigned char __user *)arg,
765 &mldl_cfg->inv_mpu_state->i2c_slaves_enabled,
766 sizeof(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)))
767 retval = -EFAULT;
768 break;
769 default:
770 dev_err(&client->adapter->dev,
771 "%s: Unknown cmd %x, arg %lu\n",
772 __func__, cmd, arg);
773 retval = -EINVAL;
774 };
775
776 mutex_unlock(&mpu->mutex);
777 dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",
778 __func__, cmd, arg, retval);
779
780 if (retval > 0)
781 retval = -retval;
782
783 return retval;
784}
785
786void mpu_shutdown(struct i2c_client *client)
787{
788 struct mpu_private_data *mpu =
789 (struct mpu_private_data *)i2c_get_clientdata(client);
790 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
791 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
792 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
793 int ii;
794
795 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
796 if (!pdata_slave[ii])
797 slave_adapter[ii] = NULL;
798 else
799 slave_adapter[ii] =
800 i2c_get_adapter(pdata_slave[ii]->adapt_num);
801 }
802 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
803
804 mutex_lock(&mpu->mutex);
805 (void)inv_mpu_suspend(mldl_cfg,
806 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
807 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
808 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
809 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
810 INV_ALL_SENSORS);
811 mutex_unlock(&mpu->mutex);
812 dev_dbg(&client->adapter->dev, "%s\n", __func__);
813}
814
815int mpu_dev_suspend(struct i2c_client *client, pm_message_t mesg)
816{
817 struct mpu_private_data *mpu =
818 (struct mpu_private_data *)i2c_get_clientdata(client);
819 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
820 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
821 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
822 int ii;
823
824 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
825 if (!pdata_slave[ii])
826 slave_adapter[ii] = NULL;
827 else
828 slave_adapter[ii] =
829 i2c_get_adapter(pdata_slave[ii]->adapt_num);
830 }
831 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
832
833 mutex_lock(&mpu->mutex);
834 if (!mldl_cfg->inv_mpu_cfg->ignore_system_suspend) {
835 dev_dbg(&client->adapter->dev,
836 "%s: suspending on event %d\n", __func__, mesg.event);
837 (void)inv_mpu_suspend(mldl_cfg,
838 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
839 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
840 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
841 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
842 INV_ALL_SENSORS);
843 } else {
844 dev_dbg(&client->adapter->dev,
845 "%s: Already suspended %d\n", __func__, mesg.event);
846 }
847 mutex_unlock(&mpu->mutex);
848 return 0;
849}
850
851int mpu_dev_resume(struct i2c_client *client)
852{
853 struct mpu_private_data *mpu =
854 (struct mpu_private_data *)i2c_get_clientdata(client);
855 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
856 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
857 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
858 int ii;
859
860 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
861 if (!pdata_slave[ii])
862 slave_adapter[ii] = NULL;
863 else
864 slave_adapter[ii] =
865 i2c_get_adapter(pdata_slave[ii]->adapt_num);
866 }
867 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
868
869 mutex_lock(&mpu->mutex);
870 if (mpu->pid && !mldl_cfg->inv_mpu_cfg->ignore_system_suspend) {
871 (void)inv_mpu_resume(mldl_cfg,
872 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
873 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
874 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
875 slave_adapter[EXT_SLAVE_TYPE_PRESSURE],
876 mldl_cfg->inv_mpu_cfg->requested_sensors);
877 dev_dbg(&client->adapter->dev,
878 "%s for pid %d\n", __func__, mpu->pid);
879 }
880 mutex_unlock(&mpu->mutex);
881 return 0;
882}
883
884/* define which file operations are supported */
885static const struct file_operations mpu_fops = {
886 .owner = THIS_MODULE,
887 .read = mpu_read,
888 .poll = mpu_poll,
889 .unlocked_ioctl = mpu_dev_ioctl,
890 .open = mpu_dev_open,
891 .release = mpu_release,
892};
893
894int inv_mpu_register_slave(struct module *slave_module,
895 struct i2c_client *slave_client,
896 struct ext_slave_platform_data *slave_pdata,
897 struct ext_slave_descr *(*get_slave_descr)(void))
898{
899 struct mpu_private_data *mpu = mpu_private_data;
900 struct mldl_cfg *mldl_cfg;
901 struct ext_slave_descr *slave_descr;
902 struct ext_slave_platform_data **pdata_slave;
903 char *irq_name = NULL;
904 int result = 0;
905
906 if (!slave_client || !slave_pdata || !get_slave_descr)
907 return -EINVAL;
908
909 if (!mpu) {
910 dev_err(&slave_client->adapter->dev,
911 "%s: Null mpu_private_data\n", __func__);
912 return -EINVAL;
913 }
914 mldl_cfg = &mpu->mldl_cfg;
915 pdata_slave = mldl_cfg->pdata_slave;
916 slave_descr = get_slave_descr();
917
918 if (!slave_descr) {
919 dev_err(&slave_client->adapter->dev,
920 "%s: Null ext_slave_descr\n", __func__);
921 return -EINVAL;
922 }
923
924 mutex_lock(&mpu->mutex);
925 if (mpu->pid) {
926 mutex_unlock(&mpu->mutex);
927 return -EBUSY;
928 }
929
930 if (pdata_slave[slave_descr->type]) {
931 result = -EBUSY;
932 goto out_unlock_mutex;
933 }
934
935 slave_pdata->address = slave_client->addr;
936 slave_pdata->irq = slave_client->irq;
937 slave_pdata->adapt_num = i2c_adapter_id(slave_client->adapter);
938
939 dev_info(&slave_client->adapter->dev,
940 "%s: +%s Type %d: Addr: %2x IRQ: %2d, Adapt: %2d\n",
941 __func__,
942 slave_descr->name,
943 slave_descr->type,
944 slave_pdata->address,
945 slave_pdata->irq,
946 slave_pdata->adapt_num);
947
948 switch (slave_descr->type) {
949 case EXT_SLAVE_TYPE_ACCEL:
950 irq_name = "accelirq";
951 break;
952 case EXT_SLAVE_TYPE_COMPASS:
953 irq_name = "compassirq";
954 break;
955 case EXT_SLAVE_TYPE_PRESSURE:
956 irq_name = "pressureirq";
957 break;
958 default:
959 irq_name = "none";
960 };
961 if (slave_descr->init) {
962 result = slave_descr->init(slave_client->adapter,
963 slave_descr,
964 slave_pdata);
965 if (result) {
966 dev_err(&slave_client->adapter->dev,
967 "%s init failed %d\n",
968 slave_descr->name, result);
969 goto out_unlock_mutex;
970 }
971 }
972
973 pdata_slave[slave_descr->type] = slave_pdata;
974 mpu->slave_modules[slave_descr->type] = slave_module;
975 mldl_cfg->slave[slave_descr->type] = slave_descr;
976
977 goto out_unlock_mutex;
978
979out_unlock_mutex:
980 mutex_unlock(&mpu->mutex);
981
982 if (!result && irq_name && (slave_pdata->irq > 0)) {
983 int warn_result;
984 dev_info(&slave_client->adapter->dev,
985 "Installing %s irq using %d\n",
986 irq_name,
987 slave_pdata->irq);
988 warn_result = slaveirq_init(slave_client->adapter,
989 slave_pdata, irq_name);
990 if (result)
991 dev_WARN(&slave_client->adapter->dev,
992 "%s irq assigned error: %d\n",
993 slave_descr->name, warn_result);
994 } else {
995 dev_info(&slave_client->adapter->dev,
996 "%s irq not assigned: %d %d %d\n",
997 slave_descr->name,
998 result, (int)irq_name, slave_pdata->irq);
999 }
1000
1001 return result;
1002}
1003EXPORT_SYMBOL(inv_mpu_register_slave);
1004
1005void inv_mpu_unregister_slave(struct i2c_client *slave_client,
1006 struct ext_slave_platform_data *slave_pdata,
1007 struct ext_slave_descr *(*get_slave_descr)(void))
1008{
1009 struct mpu_private_data *mpu = mpu_private_data;
1010 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
1011 struct ext_slave_descr *slave_descr;
1012 int result;
1013
1014 dev_info(&slave_client->adapter->dev, "%s\n", __func__);
1015
1016 if (!slave_client || !slave_pdata || !get_slave_descr)
1017 return;
1018
1019 if (slave_pdata->irq)
1020 slaveirq_exit(slave_pdata);
1021
1022 slave_descr = get_slave_descr();
1023 if (!slave_descr)
1024 return;
1025
1026 mutex_lock(&mpu->mutex);
1027
1028 if (slave_descr->exit) {
1029 result = slave_descr->exit(slave_client->adapter,
1030 slave_descr,
1031 slave_pdata);
1032 if (result)
1033 dev_err(&slave_client->adapter->dev,
1034 "Accel exit failed %d\n", result);
1035 }
1036 mldl_cfg->slave[slave_descr->type] = NULL;
1037 mldl_cfg->pdata_slave[slave_descr->type] = NULL;
1038 mpu->slave_modules[slave_descr->type] = NULL;
1039
1040 mutex_unlock(&mpu->mutex);
1041
1042}
1043EXPORT_SYMBOL(inv_mpu_unregister_slave);
1044
1045static unsigned short normal_i2c[] = { I2C_CLIENT_END };
1046
1047static const struct i2c_device_id mpu_id[] = {
1048 {"mpu3050", 0},
1049 {"mpu6050", 0},
1050 {"mpu6050_no_accel", 0},
1051 {}
1052};
1053MODULE_DEVICE_TABLE(i2c, mpu_id);
1054
1055int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
1056{
1057 struct mpu_platform_data *pdata;
1058 struct mpu_private_data *mpu;
1059 struct mldl_cfg *mldl_cfg;
1060 int res = 0;
1061 int ii = 0;
1062 unsigned long irq_flags;
1063
1064 dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++);
1065
1066 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
1067 res = -ENODEV;
1068 goto out_check_functionality_failed;
1069 }
1070
1071 mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL);
1072 if (!mpu) {
1073 res = -ENOMEM;
1074 goto out_alloc_data_failed;
1075 }
1076 mldl_cfg = &mpu->mldl_cfg;
1077 mldl_cfg->mpu_ram = &mpu->mpu_ram;
1078 mldl_cfg->mpu_gyro_cfg = &mpu->mpu_gyro_cfg;
1079 mldl_cfg->mpu_offsets = &mpu->mpu_offsets;
1080 mldl_cfg->mpu_chip_info = &mpu->mpu_chip_info;
1081 mldl_cfg->inv_mpu_cfg = &mpu->inv_mpu_cfg;
1082 mldl_cfg->inv_mpu_state = &mpu->inv_mpu_state;
1083
1084 mldl_cfg->mpu_ram->length = MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE;
1085 mldl_cfg->mpu_ram->ram = kzalloc(mldl_cfg->mpu_ram->length, GFP_KERNEL);
1086 if (!mldl_cfg->mpu_ram->ram) {
1087 res = -ENOMEM;
1088 goto out_alloc_ram_failed;
1089 }
1090 mpu_private_data = mpu;
1091 i2c_set_clientdata(client, mpu);
1092 mpu->client = client;
1093
1094 init_waitqueue_head(&mpu->mpu_event_wait);
1095 mutex_init(&mpu->mutex);
1096 init_completion(&mpu->completion);
1097
1098 mpu->response_timeout = 60; /* Seconds */
1099 mpu->timeout.function = mpu_pm_timeout;
1100 mpu->timeout.data = (u_long) mpu;
1101 init_timer(&mpu->timeout);
1102
1103 mpu->nb.notifier_call = mpu_pm_notifier_callback;
1104 mpu->nb.priority = 0;
1105 res = register_pm_notifier(&mpu->nb);
1106 if (res) {
1107 dev_err(&client->adapter->dev,
1108 "Unable to register pm_notifier %d\n", res);
1109 goto out_register_pm_notifier_failed;
1110 }
1111
1112 pdata = (struct mpu_platform_data *)client->dev.platform_data;
1113 if (!pdata) {
1114 dev_WARN(&client->adapter->dev,
1115 "Missing platform data for mpu\n");
1116 }
1117 mldl_cfg->pdata = pdata;
1118
1119 mldl_cfg->mpu_chip_info->addr = client->addr;
1120 res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
1121
1122 if (res) {
1123 dev_err(&client->adapter->dev,
1124 "Unable to open %s %d\n", MPU_NAME, res);
1125 res = -ENODEV;
1126 goto out_whoami_failed;
1127 }
1128
1129 mpu->dev.minor = MISC_DYNAMIC_MINOR;
1130 mpu->dev.name = "mpu";
1131 mpu->dev.fops = &mpu_fops;
1132 res = misc_register(&mpu->dev);
1133 if (res < 0) {
1134 dev_err(&client->adapter->dev,
1135 "ERROR: misc_register returned %d\n", res);
1136 goto out_misc_register_failed;
1137 }
1138
1139 if (client->irq) {
1140 dev_info(&client->adapter->dev,
1141 "Installing irq using %d\n", client->irq);
1142 if (BIT_ACTL_LOW == ((mldl_cfg->pdata->int_config) & BIT_ACTL))
1143 irq_flags = IRQF_TRIGGER_FALLING;
1144 else
1145 irq_flags = IRQF_TRIGGER_RISING;
1146 res = mpuirq_init(client, mldl_cfg, irq_flags);
1147
1148 if (res)
1149 goto out_mpuirq_failed;
1150 } else {
1151 dev_WARN(&client->adapter->dev,
1152 "Missing %s IRQ\n", MPU_NAME);
1153 }
1154 return res;
1155
1156out_mpuirq_failed:
1157 misc_deregister(&mpu->dev);
1158out_misc_register_failed:
1159 inv_mpu_close(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
1160out_whoami_failed:
1161 unregister_pm_notifier(&mpu->nb);
1162out_register_pm_notifier_failed:
1163 kfree(mldl_cfg->mpu_ram->ram);
1164 mpu_private_data = NULL;
1165out_alloc_ram_failed:
1166 kfree(mpu);
1167out_alloc_data_failed:
1168out_check_functionality_failed:
1169 dev_err(&client->adapter->dev, "%s failed %d\n", __func__, res);
1170 return res;
1171
1172}
1173
1174static int mpu_remove(struct i2c_client *client)
1175{
1176 struct mpu_private_data *mpu = i2c_get_clientdata(client);
1177 struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES];
1178 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
1179 struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave;
1180 int ii;
1181
1182 for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) {
1183 if (!pdata_slave[ii])
1184 slave_adapter[ii] = NULL;
1185 else
1186 slave_adapter[ii] =
1187 i2c_get_adapter(pdata_slave[ii]->adapt_num);
1188 }
1189
1190 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
1191 dev_dbg(&client->adapter->dev, "%s\n", __func__);
1192
1193 inv_mpu_close(mldl_cfg,
1194 slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
1195 slave_adapter[EXT_SLAVE_TYPE_ACCEL],
1196 slave_adapter[EXT_SLAVE_TYPE_COMPASS],
1197 slave_adapter[EXT_SLAVE_TYPE_PRESSURE]);
1198
1199
1200 if (client->irq)
1201 mpuirq_exit();
1202
1203 misc_deregister(&mpu->dev);
1204
1205 unregister_pm_notifier(&mpu->nb);
1206
1207 kfree(mpu->mldl_cfg.mpu_ram->ram);
1208 kfree(mpu);
1209
1210 return 0;
1211}
1212
1213static struct i2c_driver mpu_driver = {
1214 .class = I2C_CLASS_HWMON,
1215 .probe = mpu_probe,
1216 .remove = mpu_remove,
1217 .id_table = mpu_id,
1218 .driver = {
1219 .owner = THIS_MODULE,
1220 .name = MPU_NAME,
1221 },
1222 .address_list = normal_i2c,
1223 .shutdown = mpu_shutdown, /* optional */
1224 .suspend = mpu_dev_suspend, /* optional */
1225 .resume = mpu_dev_resume, /* optional */
1226
1227};
1228
1229static int __init mpu_init(void)
1230{
1231 int res = i2c_add_driver(&mpu_driver);
1232 pr_info("%s: Probe name %s\n", __func__, MPU_NAME);
1233 if (res)
1234 pr_err("%s failed\n", __func__);
1235 return res;
1236}
1237
1238static void __exit mpu_exit(void)
1239{
1240 pr_info("%s\n", __func__);
1241 i2c_del_driver(&mpu_driver);
1242}
1243
1244module_init(mpu_init);
1245module_exit(mpu_exit);
1246
1247MODULE_AUTHOR("Invensense Corporation");
1248MODULE_DESCRIPTION("User space character device interface for MPU");
1249MODULE_LICENSE("GPL");
1250MODULE_ALIAS(MPU_NAME);