]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/meta-ti-glsdk.git/blob - recipes-bsp/linux/linux-omap-psp-2.6.32/omap3-touchbook/0002-MMA7455L-accelerometer-driver.patch
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.
22  
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
42  
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 +};
134 +enum mma7455l_reg_status {
135 +       MMA7455L_STATUS_XDA             = 0x08,
136 +       MMA7455L_STATUS_YDA             = 0x10,
137 +       MMA7455L_STATUS_ZDA             = 0x20,
138 +};
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 +};
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 +};
155 +/* FIXME */
156 +#define MMA7455L_F_FS                  0x0020  /* ADC full scale */
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;
164 +       u8 mode;
165 +       u8 gSelect;
167 +       u8 flags;
168 +       u8 working;
169 +};
171 +/* lowlevel register access functions */
173 +#define WRITE_BIT      (1 << 7)
174 +#define ADDR_SHIFT     1
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;
181 +       cmd = ((reg & 0x3f) << ADDR_SHIFT);
182 +       rc = spi_w8r8(mma->spi_dev, cmd);
184 +       return rc;
185 +}
187 +static u_int8_t reg_read(struct mma7455l_info *mma, u_int8_t reg)
188 +{
189 +       u_int8_t ret;
191 +       mutex_lock(&mma->lock);
192 +       ret = __reg_read(mma, reg);
193 +       mutex_unlock(&mma->lock);
195 +       return ret;
196 +}
198 +static s16 __reg_read_10(struct mma7455l_info *mma, u8 reg1, u8 reg2)
199 +{
200 +       u8 v1, v2;
202 +       v1 = __reg_read(mma, reg1);
203 +       v2 = __reg_read(mma, reg2);
205 +       return (v2 & 0x4) << 13 | (v2 & 0x3) << 8 | v1;
206 +}
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];
212 +       buf[0] = ((reg & 0x3f) << ADDR_SHIFT) | WRITE_BIT;
213 +       buf[1] = val;
215 +       return spi_write(mma->spi_dev, buf, sizeof(buf));
216 +}
218 +static int reg_write(struct mma7455l_info *mma, u_int8_t reg, u_int8_t val)
219 +{
220 +       int ret;
222 +       mutex_lock(&mma->lock);
223 +       ret = __reg_write(mma, reg, val);
224 +       mutex_unlock(&mma->lock);
226 +       return ret;
227 +}
229 +static s16 __reg_write_10(struct mma7455l_info *mma, u8 reg1, u8 reg2, s16 value)
230 +{
231 +       int ret;
232 +       u8 v1, v2;
234 +       v1 = value & 0xFF;
235 +       if(value < 0)
236 +               v2 = ((value >> 8) & 0x3) | 0x4;
237 +       else
238 +               v2 = 0;
240 +       ret = __reg_write(mma, reg1, v1);
241 +       ret = __reg_write(mma, reg2, v2);
242 +       return ret;
243 +}
245 +static void mma7455l_work(struct work_struct *work)
246 +{
247 +       struct mma7455l_info *mma =
248 +                       container_of(work, struct mma7455l_info, work.work);
250 +       s8 val;
251 +       mma->working = 1;
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 +       }
267 +       mma->working = 0;
268 +       input_sync(mma->input_dev);
269 +       put_device(&mma->spi_dev->dev);
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 +}
277 +static void mma7455l_schedule_work(struct mma7455l_info *mma)
278 +{
279 +       int status;
281 +       get_device(&mma->spi_dev->dev);
282 +       status = schedule_delayed_work(&mma->work, HZ / 10);
283 +}
285 +static irqreturn_t mma7455l_interrupt(int irq, void *_mma)
286 +{
287 +       struct mma7455l_info *mma = _mma;
289 +       /* Disable any further interrupts until we have processed
290 +        * the current one */
291 +       disable_irq_nosync(mma->spi_dev->irq);
293 +       mma7455l_schedule_work(mma);
294 +       return IRQ_HANDLED;
295 +}
297 +/* sysfs */ 
299 +static void get_mode(struct mma7455l_info *mma, u8 *mode, u8 *gSelect)
300 +{
301 +       u8 tmp = reg_read(mma, MMA7455L_REG_MCTL);
303 +       *mode = tmp & MMA7455L_MODE_MASK;
304 +       *gSelect = tmp & MMA7455L_GSELECT_MASK;
305 +}
307 +static void set_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
308 +{
309 +       reg_write(mma, MMA7455L_REG_MCTL, mode | gSelect);
310 +}
312 +static void update_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
313 +{
314 +       mma->mode = mode;
315 +       mma->gSelect = gSelect;
317 +       reg_write(mma, MMA7455L_REG_MCTL, mma->mode | mma->gSelect);
318 +}
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;
326 +       get_mode(mma, &old_Mode, &old_gSelect);
327 +       set_mode(mma, MMA7455L_MODE_MEASUREMENT, MMA7455L_GSELECT_2);
329 +       while (reg_read(mma, MMA7455L_REG_STATUS) == 0) {
330 +               msleep(10);
331 +       }
333 +       x = reg_read(mma, MMA7455L_REG_XOUT8);
334 +       y = reg_read(mma, MMA7455L_REG_YOUT8);
335 +       z = reg_read(mma, MMA7455L_REG_ZOUT8);
337 +       set_mode(mma, old_Mode, old_gSelect);
338 +       return sprintf(buf, "%d %d %d\n", x, y, z);
339 +}
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);
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 +       }
361 +       return sprintf(buf, "Unknown mode!\n");
362 +}
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);
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 +       }
381 +       return sprintf(buf, "Unknown gSelect!\n");
382 +}
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 +}
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);
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);
401 +       return sprintf(buf, "%d %d %d\n", x, y, z);
402 +}
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);
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);
417 +       return count;
418 +}
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);
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 +       }
445 +       return -EINVAL;
446 +}
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);
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 +       }
462 +       return -EINVAL;
463 +}
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);
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);
478 +               return count;
479 +       }
481 +       return -EINVAL;
482 +}
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);
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 +};
499 +static struct attribute_group mma7455l_attr_group = {
500 +        .attrs  = mma7455l_sysfs_entries,
501 +};
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);
510 +       return 0;
511 +}
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 +}
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;
526 +       mma = kzalloc(sizeof(*mma), GFP_KERNEL);
527 +       if (!mma)
528 +               return -ENOMEM;
530 +       mutex_init(&mma->lock);
531 +       INIT_DELAYED_WORK(&mma->work, mma7455l_work);
532 +       mma->spi_dev = spi;
533 +       mma->flags = mma->working = 0;
535 +       spi_set_drvdata(spi, mma);
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 +       }
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 +       }
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 +       }
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 +        }
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 +       }
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);
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;
585 +       rc = input_register_device(mma->input_dev);
586 +       if(!rc)
587 +       {
588 +               update_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
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);
596 +               return 0;
597 +       }
599 +       input_free_device(mma->input_dev);
600 +       return rc;
601 +}
603 +static int __devexit mma7455l_remove(struct spi_device *spi)
604 +{
605 +       struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
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);
612 +       return 0;
613 +}
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);
622 +       return 0;
623 +}
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);
630 +       return 0;
631 +}
632 +#else
633 +#define mma7455l_suspend NULL
634 +#define mma7455l_resume  NULL
635 +#endif
637 +static struct spi_driver mma7455l_driver = {
638 +       .driver = {
639 +               .name   = "mma7455l",
640 +               .owner  = THIS_MODULE,
641 +       },
643 +       .probe   = mma7455l_probe,
644 +       .remove  = __devexit_p(mma7455l_remove),
645 +       .suspend = mma7455l_suspend,
646 +       .resume  = mma7455l_resume,
647 +};
649 +static int __init mma7455l_init(void)
650 +{
651 +       return spi_register_driver(&mma7455l_driver);
652 +}
654 +static void __exit mma7455l_exit(void)
655 +{
656 +       spi_unregister_driver(&mma7455l_driver);
657 +}
659 +MODULE_AUTHOR("Gregoire Gentil <gregoire@gentil.com>");
660 +MODULE_LICENSE("GPL");
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
673 +struct mma7455l_platform_data {
674 +       /* Calibration offsets */
675 +       s16 calibration_x;
676 +       s16 calibration_y;
677 +       s16 calibration_z;
678 +};
680 +#endif /* _LINUX_MMA7455L_H */
681 -- 
682 1.6.6.1