f9c7702e9e530a54c1d226c45acd9094f2eb4073
[glsdk/meta-ti-glsdk.git] / recipes-bsp / linux / linux-omap-psp-2.6.32 / omap3-touchbook / 0002-MMA7455L-accelerometer-driver.patch
1 From 0c804b06c04a14da575d592c89408537c21fb26b Mon Sep 17 00:00:00 2001
2 From: Tim Yamin <plasm@roo.me.uk>
3 Date: Tue, 23 Mar 2010 09:52:10 +0100
4 Subject: [PATCH 02/17] MMA7455L accelerometer driver
6 ---
7 drivers/input/misc/Kconfig | 9 +
8 drivers/input/misc/Makefile | 1 +
9 drivers/input/misc/mma7455l.c | 615 +++++++++++++++++++++++++++++++++++++++++
10 include/linux/mma7455l.h | 11 +
11 4 files changed, 636 insertions(+), 0 deletions(-)
12 create mode 100644 drivers/input/misc/mma7455l.c
13 create mode 100644 include/linux/mma7455l.h
15 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
16 index 16ec523..d35ae19 100644
17 --- a/drivers/input/misc/Kconfig
18 +++ b/drivers/input/misc/Kconfig
19 @@ -319,4 +319,13 @@ config INPUT_PCAP
20 To compile this driver as a module, choose M here: the
21 module will be called pcap_keys.
23 +config INPUT_MMA7455L
24 + tristate "Freescale MMA7455L 3-axis accelerometer"
25 + depends on SPI_MASTER
26 + help
27 + SPI driver for the Freescale MMA7455L 3-axis accelerometer.
28 +
29 + The userspace interface is a 3-axis (X/Y/Z) relative movement
30 + Linux input device, reporting REL_[XYZ] events.
31 +
32 endif
33 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
34 index a8b8485..75b8baa 100644
35 --- a/drivers/input/misc/Makefile
36 +++ b/drivers/input/misc/Makefile
37 @@ -30,4 +30,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
38 obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
39 obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
40 obj-$(CONFIG_INPUT_YEALINK) += yealink.o
41 +obj-$(CONFIG_INPUT_MMA7455L) += mma7455l.o
43 diff --git a/drivers/input/misc/mma7455l.c b/drivers/input/misc/mma7455l.c
44 new file mode 100644
45 index 0000000..b907cc6
46 --- /dev/null
47 +++ b/drivers/input/misc/mma7455l.c
48 @@ -0,0 +1,615 @@
49 +/* Linux kernel driver for the Freescale MMA7455L 3-axis accelerometer
50 + *
51 + * Copyright (C) 2009 by Always Innovating, Inc.
52 + * Author: Gregoire Gentil <gregoire@gentil.com>
53 + * Author: Tim Yamin <plasm@roo.me.uk>
54 + * All rights reserved.
55 + *
56 + * This program is free software; you can redistribute it and/or
57 + * modify it under the terms of the GNU General Public License as
58 + * published by the Free Software Foundation; either version 2 of
59 + * the License, or (at your option) any later version.
60 + *
61 + * This program is distributed in the hope that it will be useful,
62 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
63 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
64 + * GNU General Public License for more details.
65 + *
66 + * You should have received a copy of the GNU General Public License
67 + * along with this program; if not, write to the Free Software
68 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
69 + * MA 02111-1307 USA
70 + *
71 + */
72 +
73 +/*
74 + * What this driver doesn't yet support:
75 + *
76 + * - I2C
77 + * - INT2 handling
78 + * - Pulse detection (and the sysctls to control it)
79 + * - 10-bit measurement
80 + */
81 +
82 +#include <linux/kernel.h>
83 +#include <linux/types.h>
84 +#include <linux/module.h>
85 +#include <linux/device.h>
86 +#include <linux/platform_device.h>
87 +#include <linux/delay.h>
88 +#include <linux/input.h>
89 +#include <linux/irq.h>
90 +#include <linux/interrupt.h>
91 +#include <linux/sysfs.h>
92 +#include <linux/gpio.h>
93 +
94 +#include <linux/mma7455l.h>
95 +#include <linux/spi/spi.h>
96 +
97 +#define MMA7455L_WHOAMI_MAGIC 0x55
98 +
99 +enum mma7455l_reg {
100 + MMA7455L_REG_XOUTL = 0x00,
101 + MMA7455L_REG_XOUTH = 0x01,
102 + MMA7455L_REG_YOUTL = 0x02,
103 + MMA7455L_REG_YOUTH = 0x03,
104 + MMA7455L_REG_ZOUTL = 0x04,
105 + MMA7455L_REG_ZOUTH = 0x05,
106 + MMA7455L_REG_XOUT8 = 0x06,
107 + MMA7455L_REG_YOUT8 = 0x07,
108 + MMA7455L_REG_ZOUT8 = 0x08,
109 + MMA7455L_REG_STATUS = 0x09,
110 + MMA7455L_REG_DETSRC = 0x0a,
111 + MMA7455L_REG_TOUT = 0x0b,
112 + MMA7455L_REG_RESERVED1 = 0x0c,
113 + MMA7455L_REG_I2CAD = 0x0d,
114 + MMA7455L_REG_USRINF = 0x0e,
115 + MMA7455L_REG_WHOAMI = 0x0f,
116 + MMA7455L_REG_XOFFL = 0x10,
117 + MMA7455L_REG_XOFFH = 0x11,
118 + MMA7455L_REG_YOFFL = 0x12,
119 + MMA7455L_REG_YOFFH = 0x13,
120 + MMA7455L_REG_ZOFFL = 0x14,
121 + MMA7455L_REG_ZOFFH = 0x15,
122 + MMA7455L_REG_MCTL = 0x16,
123 + MMA7455L_REG_INTRST = 0x17,
124 + MMA7455L_REG_CTL1 = 0x18,
125 + MMA7455L_REG_CTL2 = 0x19,
126 + MMA7455L_REG_LDTH = 0x1a,
127 + MMA7455L_REG_PDTH = 0x1b,
128 + MMA7455L_REG_PW = 0x1c,
129 + MMA7455L_REG_LT = 0x1d,
130 + MMA7455L_REG_TW = 0x1e,
131 + MMA7455L_REG_RESERVED2 = 0x1f,
132 +};
133 +
134 +enum mma7455l_reg_status {
135 + MMA7455L_STATUS_XDA = 0x08,
136 + MMA7455L_STATUS_YDA = 0x10,
137 + MMA7455L_STATUS_ZDA = 0x20,
138 +};
139 +
140 +enum mma7455l_mode {
141 + MMA7455L_MODE_STANDBY = 0,
142 + MMA7455L_MODE_MEASUREMENT = 1,
143 + MMA7455L_MODE_LEVELDETECTION = 0x42, /* Set DRPD to on */
144 + MMA7455L_MODE_PULSEDETECTION = 0x43, /* Set DRPD to on */
145 + MMA7455L_MODE_MASK = 0x43,
146 +};
147 +
148 +enum mma7455l_gselect {
149 + MMA7455L_GSELECT_8 = 0x0,
150 + MMA7455L_GSELECT_2 = 0x4,
151 + MMA7455L_GSELECT_4 = 0x8,
152 + MMA7455L_GSELECT_MASK = 0xC,
153 +};
154 +
155 +/* FIXME */
156 +#define MMA7455L_F_FS 0x0020 /* ADC full scale */
157 +
158 +struct mma7455l_info {
159 + struct spi_device *spi_dev;
160 + struct input_dev *input_dev;
161 + struct mutex lock;
162 + struct delayed_work work;
163 +
164 + u8 mode;
165 + u8 gSelect;
166 +
167 + u8 flags;
168 + u8 working;
169 +};
170 +
171 +/* lowlevel register access functions */
172 +
173 +#define WRITE_BIT (1 << 7)
174 +#define ADDR_SHIFT 1
175 +
176 +static inline u_int8_t __reg_read(struct mma7455l_info *mma, u_int8_t reg)
177 +{
178 + int rc;
179 + u_int8_t cmd;
180 +
181 + cmd = ((reg & 0x3f) << ADDR_SHIFT);
182 + rc = spi_w8r8(mma->spi_dev, cmd);
183 +
184 + return rc;
185 +}
186 +
187 +static u_int8_t reg_read(struct mma7455l_info *mma, u_int8_t reg)
188 +{
189 + u_int8_t ret;
190 +
191 + mutex_lock(&mma->lock);
192 + ret = __reg_read(mma, reg);
193 + mutex_unlock(&mma->lock);
194 +
195 + return ret;
196 +}
197 +
198 +static s16 __reg_read_10(struct mma7455l_info *mma, u8 reg1, u8 reg2)
199 +{
200 + u8 v1, v2;
201 +
202 + v1 = __reg_read(mma, reg1);
203 + v2 = __reg_read(mma, reg2);
204 +
205 + return (v2 & 0x4) << 13 | (v2 & 0x3) << 8 | v1;
206 +}
207 +
208 +static inline int __reg_write(struct mma7455l_info *mma, u_int8_t reg, u_int8_t val)
209 +{
210 + u_int8_t buf[2];
211 +
212 + buf[0] = ((reg & 0x3f) << ADDR_SHIFT) | WRITE_BIT;
213 + buf[1] = val;
214 +
215 + return spi_write(mma->spi_dev, buf, sizeof(buf));
216 +}
217 +
218 +static int reg_write(struct mma7455l_info *mma, u_int8_t reg, u_int8_t val)
219 +{
220 + int ret;
221 +
222 + mutex_lock(&mma->lock);
223 + ret = __reg_write(mma, reg, val);
224 + mutex_unlock(&mma->lock);
225 +
226 + return ret;
227 +}
228 +
229 +static s16 __reg_write_10(struct mma7455l_info *mma, u8 reg1, u8 reg2, s16 value)
230 +{
231 + int ret;
232 + u8 v1, v2;
233 +
234 + v1 = value & 0xFF;
235 + if(value < 0)
236 + v2 = ((value >> 8) & 0x3) | 0x4;
237 + else
238 + v2 = 0;
239 +
240 + ret = __reg_write(mma, reg1, v1);
241 + ret = __reg_write(mma, reg2, v2);
242 + return ret;
243 +}
244 +
245 +static void mma7455l_work(struct work_struct *work)
246 +{
247 + struct mma7455l_info *mma =
248 + container_of(work, struct mma7455l_info, work.work);
249 +
250 + s8 val;
251 + mma->working = 1;
252 +
253 + /* FIXME: 10 bit accuracy? */
254 + if (!(mma->flags & MMA7455L_STATUS_XDA)) {
255 + val = reg_read(mma, MMA7455L_REG_XOUT8);
256 + input_report_abs(mma->input_dev, ABS_X, val);
257 + }
258 + if (!(mma->flags & MMA7455L_STATUS_YDA)) {
259 + val = reg_read(mma, MMA7455L_REG_YOUT8);
260 + input_report_abs(mma->input_dev, ABS_Y, val);
261 + }
262 + if (!(mma->flags & MMA7455L_STATUS_ZDA)) {
263 + val = reg_read(mma, MMA7455L_REG_ZOUT8);
264 + input_report_abs(mma->input_dev, ABS_Z, val);
265 + }
266 +
267 + mma->working = 0;
268 + input_sync(mma->input_dev);
269 + put_device(&mma->spi_dev->dev);
270 +
271 + /* Enable IRQ and clear out interrupt */
272 + reg_write(mma, MMA7455L_REG_INTRST, 0x3);
273 + reg_write(mma, MMA7455L_REG_INTRST, 0x0);
274 + enable_irq(mma->spi_dev->irq);
275 +}
276 +
277 +static void mma7455l_schedule_work(struct mma7455l_info *mma)
278 +{
279 + int status;
280 +
281 + get_device(&mma->spi_dev->dev);
282 + status = schedule_delayed_work(&mma->work, HZ / 10);
283 +}
284 +
285 +static irqreturn_t mma7455l_interrupt(int irq, void *_mma)
286 +{
287 + struct mma7455l_info *mma = _mma;
288 +
289 + /* Disable any further interrupts until we have processed
290 + * the current one */
291 + disable_irq_nosync(mma->spi_dev->irq);
292 +
293 + mma7455l_schedule_work(mma);
294 + return IRQ_HANDLED;
295 +}
296 +
297 +/* sysfs */
298 +
299 +static void get_mode(struct mma7455l_info *mma, u8 *mode, u8 *gSelect)
300 +{
301 + u8 tmp = reg_read(mma, MMA7455L_REG_MCTL);
302 +
303 + *mode = tmp & MMA7455L_MODE_MASK;
304 + *gSelect = tmp & MMA7455L_GSELECT_MASK;
305 +}
306 +
307 +static void set_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
308 +{
309 + reg_write(mma, MMA7455L_REG_MCTL, mode | gSelect);
310 +}
311 +
312 +static void update_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
313 +{
314 + mma->mode = mode;
315 + mma->gSelect = gSelect;
316 +
317 + reg_write(mma, MMA7455L_REG_MCTL, mma->mode | mma->gSelect);
318 +}
319 +
320 +static ssize_t show_measure(struct device *dev, struct device_attribute *attr, char *buf)
321 +{
322 + struct mma7455l_info *mma = dev_get_drvdata(dev);
323 + s8 x, y, z;
324 + u8 old_Mode, old_gSelect;
325 +
326 + get_mode(mma, &old_Mode, &old_gSelect);
327 + set_mode(mma, MMA7455L_MODE_MEASUREMENT, MMA7455L_GSELECT_2);
328 +
329 + while (reg_read(mma, MMA7455L_REG_STATUS) == 0) {
330 + msleep(10);
331 + }
332 +
333 + x = reg_read(mma, MMA7455L_REG_XOUT8);
334 + y = reg_read(mma, MMA7455L_REG_YOUT8);
335 + z = reg_read(mma, MMA7455L_REG_ZOUT8);
336 +
337 + set_mode(mma, old_Mode, old_gSelect);
338 + return sprintf(buf, "%d %d %d\n", x, y, z);
339 +}
340 +
341 +static ssize_t show_mode(struct device *dev, struct device_attribute *attr, char *buf)
342 +{
343 + struct mma7455l_info *mma = dev_get_drvdata(dev);
344 +
345 + switch(mma->mode)
346 + {
347 + case MMA7455L_MODE_STANDBY:
348 + return sprintf(buf, "Standby\n");
349 + break;
350 + case MMA7455L_MODE_MEASUREMENT:
351 + return sprintf(buf, "Measurement\n");
352 + break;
353 + case MMA7455L_MODE_LEVELDETECTION:
354 + return sprintf(buf, "Level Detection\n");
355 + break;
356 + case MMA7455L_MODE_PULSEDETECTION:
357 + return sprintf(buf, "Pulse Detection\n");
358 + break;
359 + }
360 +
361 + return sprintf(buf, "Unknown mode!\n");
362 +}
363 +
364 +static ssize_t show_gSelect(struct device *dev, struct device_attribute *attr, char *buf)
365 +{
366 + struct mma7455l_info *mma = dev_get_drvdata(dev);
367 +
368 + switch(mma->gSelect)
369 + {
370 + case MMA7455L_GSELECT_8:
371 + return sprintf(buf, "8\n");
372 + break;
373 + case MMA7455L_GSELECT_4:
374 + return sprintf(buf, "4\n");
375 + break;
376 + case MMA7455L_GSELECT_2:
377 + return sprintf(buf, "2\n");
378 + break;
379 + }
380 +
381 + return sprintf(buf, "Unknown gSelect!\n");
382 +}
383 +
384 +static ssize_t show_level_threshold(struct device *dev, struct device_attribute *attr, char *buf)
385 +{
386 + struct mma7455l_info *mma = dev_get_drvdata(dev);
387 + return sprintf(buf, "%u\n", reg_read(mma, MMA7455L_REG_LDTH));
388 +}
389 +
390 +static ssize_t show_calibration(struct device *dev, struct device_attribute *attr, char *buf)
391 +{
392 + s16 x, y, z;
393 + struct mma7455l_info *mma = dev_get_drvdata(dev);
394 +
395 + mutex_lock(&mma->lock);
396 + x = __reg_read_10(mma, MMA7455L_REG_XOFFL, MMA7455L_REG_XOFFH);
397 + y = __reg_read_10(mma, MMA7455L_REG_YOFFL, MMA7455L_REG_YOFFH);
398 + z = __reg_read_10(mma, MMA7455L_REG_ZOFFL, MMA7455L_REG_ZOFFH);
399 + mutex_unlock(&mma->lock);
400 +
401 + return sprintf(buf, "%d %d %d\n", x, y, z);
402 +}
403 +
404 +static ssize_t write_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
405 +{
406 + struct mma7455l_info *mma = dev_get_drvdata(dev);
407 +
408 + if (!strncmp(buf, "Standby", count))
409 + update_mode(mma, MMA7455L_MODE_STANDBY, mma->gSelect);
410 + else if (!strncmp(buf, "Measurement", count))
411 + update_mode(mma, MMA7455L_MODE_MEASUREMENT, mma->gSelect);
412 + else if (!strncmp(buf, "Level Detection", count))
413 + update_mode(mma, MMA7455L_MODE_LEVELDETECTION, mma->gSelect);
414 + else if (!strncmp(buf, "Pulse Detection", count))
415 + update_mode(mma, MMA7455L_MODE_PULSEDETECTION, mma->gSelect);
416 +
417 + return count;
418 +}
419 +
420 +static ssize_t write_gSelect(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
421 +{
422 + unsigned long v;
423 + struct mma7455l_info *mma = dev_get_drvdata(dev);
424 +
425 + if(strict_strtoul(buf, 10, &v) == 0)
426 + {
427 + switch(v)
428 + {
429 + case 8:
430 + update_mode(mma, mma->mode, MMA7455L_GSELECT_8);
431 + break;
432 + case 4:
433 + update_mode(mma, mma->mode, MMA7455L_GSELECT_4);
434 + break;
435 + case 2:
436 + update_mode(mma, mma->mode, MMA7455L_GSELECT_2);
437 + break;
438 + default:
439 + return -EINVAL;
440 + break;
441 + }
442 + return count;
443 + }
444 +
445 + return -EINVAL;
446 +}
447 +
448 +static ssize_t write_level_threshold(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
449 +{
450 + unsigned long v;
451 + struct mma7455l_info *mma = dev_get_drvdata(dev);
452 +
453 + if(strict_strtoul(buf, 10, &v) == 0)
454 + {
455 + if(v <= 0xFF) {
456 + reg_write(mma, MMA7455L_REG_LDTH, v);
457 + return count;
458 + } else
459 + return -EINVAL;
460 + }
461 +
462 + return -EINVAL;
463 +}
464 +
465 +static ssize_t write_calibration(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
466 +{
467 + int x, y, z;
468 + struct mma7455l_info *mma = dev_get_drvdata(dev);
469 +
470 + if (sscanf(buf, "%d %d %d", &x, &y, &z) == 3)
471 + {
472 + mutex_lock(&mma->lock);
473 + __reg_write_10(mma, MMA7455L_REG_XOFFL, MMA7455L_REG_XOFFH, x);
474 + __reg_write_10(mma, MMA7455L_REG_YOFFL, MMA7455L_REG_YOFFH, y);
475 + __reg_write_10(mma, MMA7455L_REG_ZOFFL, MMA7455L_REG_ZOFFH, z);
476 + mutex_unlock(&mma->lock);
477 +
478 + return count;
479 + }
480 +
481 + return -EINVAL;
482 +}
483 +
484 +static DEVICE_ATTR(measure, S_IRUGO, show_measure, NULL);
485 +static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, write_mode);
486 +static DEVICE_ATTR(gSelect, S_IRUGO | S_IWUGO, show_gSelect, write_gSelect);
487 +static DEVICE_ATTR(level_threshold, S_IRUGO | S_IWUGO, show_level_threshold, write_level_threshold);
488 +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUGO, show_calibration, write_calibration);
489 +
490 +static struct attribute *mma7455l_sysfs_entries[] = {
491 + &dev_attr_measure.attr,
492 + &dev_attr_mode.attr,
493 + &dev_attr_gSelect.attr,
494 + &dev_attr_level_threshold.attr,
495 + &dev_attr_calibration.attr,
496 + NULL
497 +};
498 +
499 +static struct attribute_group mma7455l_attr_group = {
500 + .attrs = mma7455l_sysfs_entries,
501 +};
502 +
503 +/* input device handling and driver core interaction */
504 +static int mma7455l_input_open(struct input_dev *inp)
505 +{
506 + struct mma7455l_info *mma = input_get_drvdata(inp);
507 + if(mma->mode == MMA7455L_MODE_STANDBY)
508 + update_mode(mma, MMA7455L_MODE_MEASUREMENT, mma->gSelect);
509 +
510 + return 0;
511 +}
512 +
513 +static void mma7455l_input_close(struct input_dev *inp)
514 +{
515 + struct mma7455l_info *mma = input_get_drvdata(inp);
516 + update_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
517 +}
518 +
519 +static int __devinit mma7455l_probe(struct spi_device *spi)
520 +{
521 + int rc;
522 + struct mma7455l_info *mma;
523 + struct mma7455l_platform_data *pdata = spi->dev.platform_data;
524 + u_int8_t wai;
525 +
526 + mma = kzalloc(sizeof(*mma), GFP_KERNEL);
527 + if (!mma)
528 + return -ENOMEM;
529 +
530 + mutex_init(&mma->lock);
531 + INIT_DELAYED_WORK(&mma->work, mma7455l_work);
532 + mma->spi_dev = spi;
533 + mma->flags = mma->working = 0;
534 +
535 + spi_set_drvdata(spi, mma);
536 +
537 + rc = spi_setup(spi);
538 + if (rc < 0) {
539 + printk(KERN_ERR "mma7455l error durign spi_setup of mma7455l driver\n");
540 + dev_set_drvdata(&spi->dev, NULL);
541 + kfree(mma);
542 + return rc;
543 + }
544 +
545 + wai = reg_read(mma, MMA7455L_REG_WHOAMI);
546 + if (wai != MMA7455L_WHOAMI_MAGIC) {
547 + printk(KERN_ERR "mma7455l unknown whoami signature 0x%02x\n", wai);
548 + dev_set_drvdata(&spi->dev, NULL);
549 + kfree(mma);
550 + return -ENODEV;
551 + }
552 +
553 + rc = request_irq(mma->spi_dev->irq, mma7455l_interrupt, IRQF_TRIGGER_HIGH,
554 + "mma7455l", mma);
555 + if (rc < 0) {
556 + dev_err(&spi->dev, "mma7455l error requesting IRQ %d\n",
557 + mma->spi_dev->irq);
558 + /* FIXME */
559 + return rc;
560 + }
561 +
562 + rc = sysfs_create_group(&spi->dev.kobj, &mma7455l_attr_group);
563 + if (rc) {
564 + dev_err(&spi->dev, "error creating sysfs group\n");
565 + return rc;
566 + }
567 +
568 + /* initialize input layer details */
569 + mma->input_dev = input_allocate_device();
570 + if (!mma->input_dev) {
571 + dev_err(&spi->dev, "mma7455l Unable to allocate input device\n");
572 + /* FIXME */
573 + }
574 +
575 + set_bit(EV_ABS, mma->input_dev->evbit);
576 + set_bit(ABS_X, mma->input_dev->absbit);
577 + set_bit(ABS_Y, mma->input_dev->absbit);
578 + set_bit(ABS_Z, mma->input_dev->absbit);
579 +
580 + input_set_drvdata(mma->input_dev, mma);
581 + mma->input_dev->name = "MMA7455L";
582 + mma->input_dev->open = mma7455l_input_open;
583 + mma->input_dev->close = mma7455l_input_close;
584 +
585 + rc = input_register_device(mma->input_dev);
586 + if(!rc)
587 + {
588 + update_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
589 +
590 + mutex_lock(&mma->lock);
591 + __reg_write_10(mma, MMA7455L_REG_XOFFL, MMA7455L_REG_XOFFH, pdata->calibration_x);
592 + __reg_write_10(mma, MMA7455L_REG_YOFFL, MMA7455L_REG_YOFFH, pdata->calibration_y);
593 + __reg_write_10(mma, MMA7455L_REG_ZOFFL, MMA7455L_REG_ZOFFH, pdata->calibration_z);
594 + mutex_unlock(&mma->lock);
595 +
596 + return 0;
597 + }
598 +
599 + input_free_device(mma->input_dev);
600 + return rc;
601 +}
602 +
603 +static int __devexit mma7455l_remove(struct spi_device *spi)
604 +{
605 + struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
606 +
607 + sysfs_remove_group(&spi->dev.kobj, &mma7455l_attr_group);
608 + input_unregister_device(mma->input_dev);
609 + dev_set_drvdata(&spi->dev, NULL);
610 + kfree(mma);
611 +
612 + return 0;
613 +}
614 +
615 +#ifdef CONFIG_PM
616 +static int mma7455l_suspend(struct spi_device *spi, pm_message_t message)
617 +{
618 + struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
619 + get_mode(mma, &mma->mode, &mma->gSelect);
620 + set_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
621 +
622 + return 0;
623 +}
624 +
625 +static int mma7455l_resume(struct spi_device *spi)
626 +{
627 + struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
628 + update_mode(mma, mma->mode, mma->gSelect);
629 +
630 + return 0;
631 +}
632 +#else
633 +#define mma7455l_suspend NULL
634 +#define mma7455l_resume NULL
635 +#endif
636 +
637 +static struct spi_driver mma7455l_driver = {
638 + .driver = {
639 + .name = "mma7455l",
640 + .owner = THIS_MODULE,
641 + },
642 +
643 + .probe = mma7455l_probe,
644 + .remove = __devexit_p(mma7455l_remove),
645 + .suspend = mma7455l_suspend,
646 + .resume = mma7455l_resume,
647 +};
648 +
649 +static int __init mma7455l_init(void)
650 +{
651 + return spi_register_driver(&mma7455l_driver);
652 +}
653 +
654 +static void __exit mma7455l_exit(void)
655 +{
656 + spi_unregister_driver(&mma7455l_driver);
657 +}
658 +
659 +MODULE_AUTHOR("Gregoire Gentil <gregoire@gentil.com>");
660 +MODULE_LICENSE("GPL");
661 +
662 +module_init(mma7455l_init);
663 +module_exit(mma7455l_exit);
664 diff --git a/include/linux/mma7455l.h b/include/linux/mma7455l.h
665 new file mode 100644
666 index 0000000..12ab50a
667 --- /dev/null
668 +++ b/include/linux/mma7455l.h
669 @@ -0,0 +1,11 @@
670 +#ifndef _LINUX_MMA7455L_H
671 +#define _LINUX_MMA7455L_H
672 +
673 +struct mma7455l_platform_data {
674 + /* Calibration offsets */
675 + s16 calibration_x;
676 + s16 calibration_y;
677 + s16 calibration_z;
678 +};
679 +
680 +#endif /* _LINUX_MMA7455L_H */
681 --
682 1.6.6.1