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