lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Sun, 15 Nov 2009 20:30:35 -0800
From:	Gregoire Gentil <gregoire@...til.com>
To:	linux-omap@...r.kernel.org
Cc:	Tony Lindgren <tony@...mide.com>, Tim Yamin <plasmaroo@...il.com>,
	linux-kernel@...r.kernel.org
Subject: [PATCH 3/5] AI TB: Driver for the Freescale MMA7455L accelerometer

Driver for the Freescale MMA7455L accelerometer




Signed-off-by: Gregoire Gentil <gregoire@...til.com>
---
drivers/input/misc/Kconfig    |    9 +
drivers/input/misc/Makefile   |    2 +-
drivers/input/misc/mma7455l.c |  625
+++++++++++++++++++++++++++++++++++++++++
include/linux/mma7455l.h      |   11 +
4 files changed, 646 insertions(+), 1 deletions(-)
create mode 100644 drivers/input/misc/mma7455l.c
create mode 100644 include/linux/mma7455l.h

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a9bb254..454bac7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -317,4 +317,13 @@ config INPUT_PCAP
  To compile this driver as a module, choose M here: the
  module will be called pcap_keys.

+config INPUT_MMA7455L
+ tristate "Freescale MMA7455L 3-axis accelerometer"
+ depends on SPI_MASTER
+ help
+   SPI driver for the Freescale MMA7455L 3-axis accelerometer.
+
+   The userspace interface is a 3-axis (X/Y/Z) relative movement
+   Linux input device, reporting REL_[XYZ] events.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a8b8485..3db6347 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -30,4 +30,4 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
-
+obj-$(CONFIG_INPUT_MMA7455L) += mma7455l.o
diff --git a/drivers/input/misc/mma7455l.c
b/drivers/input/misc/mma7455l.c
new file mode 100644
index 0000000..771d4b7
--- /dev/null
+++ b/drivers/input/misc/mma7455l.c
@@ -0,0 +1,625 @@
+/* Linux kernel driver for the Freescale MMA7455L 3-axis accelerometer
+ *
+ * Copyright (C) 2009 by Always Innovating, Inc.
+ * Author: Gregoire Gentil <gregoire@...til.com>
+ * Author: Tim Yamin <plasm@....me.uk>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * What this driver doesn't yet support:
+ *
+ * - I2C
+ * - INT2 handling
+ * - Pulse detection (and the sysctls to control it)
+ * - 10-bit measurement
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/gpio.h>
+
+#include <linux/mma7455l.h>
+#include <linux/spi/spi.h>
+
+#define MMA7455L_WHOAMI_MAGIC 0x55
+
+enum mma7455l_reg {
+ MMA7455L_REG_XOUTL = 0x00,
+ MMA7455L_REG_XOUTH = 0x01,
+ MMA7455L_REG_YOUTL = 0x02,
+ MMA7455L_REG_YOUTH = 0x03,
+ MMA7455L_REG_ZOUTL = 0x04,
+ MMA7455L_REG_ZOUTH = 0x05,
+ MMA7455L_REG_XOUT8 = 0x06,
+ MMA7455L_REG_YOUT8 = 0x07,
+ MMA7455L_REG_ZOUT8 = 0x08,
+ MMA7455L_REG_STATUS = 0x09,
+ MMA7455L_REG_DETSRC = 0x0a,
+ MMA7455L_REG_TOUT = 0x0b,
+ MMA7455L_REG_RESERVED1 = 0x0c,
+ MMA7455L_REG_I2CAD = 0x0d,
+ MMA7455L_REG_USRINF = 0x0e,
+ MMA7455L_REG_WHOAMI = 0x0f,
+ MMA7455L_REG_XOFFL = 0x10,
+ MMA7455L_REG_XOFFH = 0x11,
+ MMA7455L_REG_YOFFL = 0x12,
+ MMA7455L_REG_YOFFH = 0x13,
+ MMA7455L_REG_ZOFFL = 0x14,
+ MMA7455L_REG_ZOFFH = 0x15,
+ MMA7455L_REG_MCTL = 0x16,
+ MMA7455L_REG_INTRST = 0x17,
+ MMA7455L_REG_CTL1 = 0x18,
+ MMA7455L_REG_CTL2 = 0x19,
+ MMA7455L_REG_LDTH = 0x1a,
+ MMA7455L_REG_PDTH = 0x1b,
+ MMA7455L_REG_PW = 0x1c,
+ MMA7455L_REG_LT = 0x1d,
+ MMA7455L_REG_TW = 0x1e,
+ MMA7455L_REG_RESERVED2 = 0x1f,
+};
+
+enum mma7455l_reg_status {
+ MMA7455L_STATUS_XDA = 0x08,
+ MMA7455L_STATUS_YDA = 0x10,
+ MMA7455L_STATUS_ZDA = 0x20,
+};
+
+enum mma7455l_mode {
+ MMA7455L_MODE_STANDBY = 0,
+ MMA7455L_MODE_MEASUREMENT = 1,
+ MMA7455L_MODE_LEVELDETECTION = 0x42, /* Set DRPD to on */
+ MMA7455L_MODE_PULSEDETECTION = 0x43, /* Set DRPD to on */
+ MMA7455L_MODE_MASK = 0x43,
+};
+
+enum mma7455l_gselect {
+ MMA7455L_GSELECT_8 = 0x0,
+ MMA7455L_GSELECT_2 = 0x4,
+ MMA7455L_GSELECT_4 = 0x8,
+ MMA7455L_GSELECT_MASK = 0xC,
+};
+
+/* FIXME */
+#define MMA7455L_F_FS 0x0020 /* ADC full scale */
+
+struct mma7455l_info {
+ struct spi_device *spi_dev;
+ struct input_dev *input_dev;
+ struct mutex lock;
+ struct delayed_work work;
+
+ u8 mode;
+ u8 gSelect;
+
+ u8 flags;
+ u8 working;
+};
+
+/* lowlevel register access functions */
+
+#define WRITE_BIT (1 << 7)
+#define ADDR_SHIFT 1
+
+static inline u_int8_t __reg_read(struct mma7455l_info *mma, u_int8_t
reg)
+{
+ int rc;
+ u_int8_t cmd;
+
+ cmd = ((reg & 0x3f) << ADDR_SHIFT);
+ rc = spi_w8r8(mma->spi_dev, cmd);
+
+ return rc;
+}
+
+static u_int8_t reg_read(struct mma7455l_info *mma, u_int8_t reg)
+{
+ u_int8_t ret;
+
+ mutex_lock(&mma->lock);
+ ret = __reg_read(mma, reg);
+ mutex_unlock(&mma->lock);
+
+ return ret;
+}
+
+static s16 __reg_read_10(struct mma7455l_info *mma, u8 reg1, u8 reg2)
+{
+ u8 v1, v2;
+
+ v1 = __reg_read(mma, reg1);
+ v2 = __reg_read(mma, reg2);
+
+ return (v2 & 0x4) << 13 | (v2 & 0x3) << 8 | v1;
+}
+
+static inline int __reg_write(struct mma7455l_info *mma,
+ u_int8_t reg, u_int8_t val)
+{
+ u_int8_t buf[2];
+
+ buf[0] = ((reg & 0x3f) << ADDR_SHIFT) | WRITE_BIT;
+ buf[1] = val;
+
+ return spi_write(mma->spi_dev, buf, sizeof(buf));
+}
+
+static int reg_write(struct mma7455l_info *mma, u_int8_t reg, u_int8_t
val)
+{
+ int ret;
+
+ mutex_lock(&mma->lock);
+ ret = __reg_write(mma, reg, val);
+ mutex_unlock(&mma->lock);
+
+ return ret;
+}
+
+static s16 __reg_write_10(struct mma7455l_info *mma,
+ u8 reg1, u8 reg2, s16 value)
+{
+ int ret;
+ u8 v1, v2;
+
+ v1 = value & 0xFF;
+ if (value < 0)
+ v2 = ((value >> 8) & 0x3) | 0x4;
+ else
+ v2 = 0;
+
+ ret = __reg_write(mma, reg1, v1);
+ ret = __reg_write(mma, reg2, v2);
+ return ret;
+}
+
+static void mma7455l_work(struct work_struct *work)
+{
+ struct mma7455l_info *mma =
+ container_of(work, struct mma7455l_info, work.work);
+
+ s8 val;
+ mma->working = 1;
+
+ /* FIXME: 10 bit accuracy? */
+ if (!(mma->flags & MMA7455L_STATUS_XDA)) {
+ val = reg_read(mma, MMA7455L_REG_XOUT8);
+ input_report_abs(mma->input_dev, ABS_X, val);
+ }
+ if (!(mma->flags & MMA7455L_STATUS_YDA)) {
+ val = reg_read(mma, MMA7455L_REG_YOUT8);
+ input_report_abs(mma->input_dev, ABS_Y, val);
+ }
+ if (!(mma->flags & MMA7455L_STATUS_ZDA)) {
+ val = reg_read(mma, MMA7455L_REG_ZOUT8);
+ input_report_abs(mma->input_dev, ABS_Z, val);
+ }
+
+ mma->working = 0;
+ input_sync(mma->input_dev);
+ put_device(&mma->spi_dev->dev);
+
+ /* Enable IRQ and clear out interrupt */
+ reg_write(mma, MMA7455L_REG_INTRST, 0x3);
+ reg_write(mma, MMA7455L_REG_INTRST, 0x0);
+ enable_irq(mma->spi_dev->irq);
+}
+
+static void mma7455l_schedule_work(struct mma7455l_info *mma)
+{
+ int status;
+
+ get_device(&mma->spi_dev->dev);
+ status = schedule_delayed_work(&mma->work, HZ / 10);
+}
+
+static irqreturn_t mma7455l_interrupt(int irq, void *_mma)
+{
+ struct mma7455l_info *mma = _mma;
+ mma7455l_schedule_work(mma);
+
+ /* Disable any further interrupts until we have processed
+ * the current one */
+ disable_irq(mma->spi_dev->irq);
+ return IRQ_HANDLED;
+}
+
+/* sysfs */
+
+static void get_mode(struct mma7455l_info *mma, u8 *mode, u8 *gSelect)
+{
+ u8 tmp = reg_read(mma, MMA7455L_REG_MCTL);
+
+ *mode = tmp & MMA7455L_MODE_MASK;
+ *gSelect = tmp & MMA7455L_GSELECT_MASK;
+}
+
+static void set_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
+{
+ reg_write(mma, MMA7455L_REG_MCTL, mode | gSelect);
+}
+
+static void update_mode(struct mma7455l_info *mma, u8 mode, u8 gSelect)
+{
+ mma->mode = mode;
+ mma->gSelect = gSelect;
+
+ reg_write(mma, MMA7455L_REG_MCTL, mma->mode | mma->gSelect);
+}
+
+static ssize_t show_measure(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+ s8 x, y, z;
+ u8 old_Mode, old_gSelect;
+
+ get_mode(mma, &old_Mode, &old_gSelect);
+ set_mode(mma, MMA7455L_MODE_MEASUREMENT, MMA7455L_GSELECT_2);
+
+ while (reg_read(mma, MMA7455L_REG_STATUS) == 0)
+ msleep(10);
+
+ x = reg_read(mma, MMA7455L_REG_XOUT8);
+ y = reg_read(mma, MMA7455L_REG_YOUT8);
+ z = reg_read(mma, MMA7455L_REG_ZOUT8);
+
+ set_mode(mma, old_Mode, old_gSelect);
+ return sprintf(buf, "%d %d %d\n", x, y, z);
+}
+
+static ssize_t show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ switch (mma->mode) {
+ case MMA7455L_MODE_STANDBY:
+ return sprintf(buf, "Standby\n");
+ break;
+ case MMA7455L_MODE_MEASUREMENT:
+ return sprintf(buf, "Measurement\n");
+ break;
+ case MMA7455L_MODE_LEVELDETECTION:
+ return sprintf(buf, "Level Detection\n");
+ break;
+ case MMA7455L_MODE_PULSEDETECTION:
+ return sprintf(buf, "Pulse Detection\n");
+ break;
+ }
+
+ return sprintf(buf, "Unknown mode!\n");
+}
+
+static ssize_t show_gSelect(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ switch (mma->gSelect) {
+ case MMA7455L_GSELECT_8:
+ return sprintf(buf, "8\n");
+ break;
+ case MMA7455L_GSELECT_4:
+ return sprintf(buf, "4\n");
+ break;
+ case MMA7455L_GSELECT_2:
+ return sprintf(buf, "2\n");
+ break;
+ }
+
+ return sprintf(buf, "Unknown gSelect!\n");
+}
+
+static ssize_t show_level_threshold(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+ return sprintf(buf, "%u\n", reg_read(mma, MMA7455L_REG_LDTH));
+}
+
+static ssize_t show_calibration(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ s16 x, y, z;
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ mutex_lock(&mma->lock);
+ x = __reg_read_10(mma, MMA7455L_REG_XOFFL, MMA7455L_REG_XOFFH);
+ y = __reg_read_10(mma, MMA7455L_REG_YOFFL, MMA7455L_REG_YOFFH);
+ z = __reg_read_10(mma, MMA7455L_REG_ZOFFL, MMA7455L_REG_ZOFFH);
+ mutex_unlock(&mma->lock);
+
+ return sprintf(buf, "%d %d %d\n", x, y, z);
+}
+
+static ssize_t write_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ if (!strncmp(buf, "Standby", count))
+ update_mode(mma, MMA7455L_MODE_STANDBY, mma->gSelect);
+ else if (!strncmp(buf, "Measurement", count))
+ update_mode(mma, MMA7455L_MODE_MEASUREMENT, mma->gSelect);
+ else if (!strncmp(buf, "Level Detection", count))
+ update_mode(mma, MMA7455L_MODE_LEVELDETECTION, mma->gSelect);
+ else if (!strncmp(buf, "Pulse Detection", count))
+ update_mode(mma, MMA7455L_MODE_PULSEDETECTION, mma->gSelect);
+
+ return count;
+}
+
+static ssize_t write_gSelect(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long v;
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ if (strict_strtoul(buf, 10, &v) == 0) {
+ switch (v) {
+ case 8:
+ update_mode(mma, mma->mode, MMA7455L_GSELECT_8);
+ break;
+ case 4:
+ update_mode(mma, mma->mode, MMA7455L_GSELECT_4);
+ break;
+ case 2:
+ update_mode(mma, mma->mode, MMA7455L_GSELECT_2);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t write_level_threshold(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long v;
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ if (strict_strtoul(buf, 10, &v) == 0) {
+ if (v <= 0xFF) {
+ reg_write(mma, MMA7455L_REG_LDTH, v);
+ return count;
+ } else
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t write_calibration(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int x, y, z;
+ struct mma7455l_info *mma = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%d %d %d", &x, &y, &z) == 3) {
+ mutex_lock(&mma->lock);
+ __reg_write_10(mma, MMA7455L_REG_XOFFL, MMA7455L_REG_XOFFH, x);
+ __reg_write_10(mma, MMA7455L_REG_YOFFL, MMA7455L_REG_YOFFH, y);
+ __reg_write_10(mma, MMA7455L_REG_ZOFFL, MMA7455L_REG_ZOFFH, z);
+ mutex_unlock(&mma->lock);
+
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(measure, S_IRUGO, show_measure, NULL);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, write_mode);
+static DEVICE_ATTR(gSelect, S_IRUGO | S_IWUGO, show_gSelect,
write_gSelect);
+static DEVICE_ATTR(level_threshold, S_IRUGO | S_IWUGO,
show_level_threshold,
+ write_level_threshold);
+static DEVICE_ATTR(calibration, S_IRUGO | S_IWUGO, show_calibration,
+ write_calibration);
+
+static struct attribute *mma7455l_sysfs_entries[] = {
+       &dev_attr_measure.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_gSelect.attr,
+ &dev_attr_level_threshold.attr,
+ &dev_attr_calibration.attr,
+ NULL
+};
+
+static struct attribute_group mma7455l_attr_group = {
+       .attrs  = mma7455l_sysfs_entries,
+};
+
+/* input device handling and driver core interaction */
+static int mma7455l_input_open(struct input_dev *inp)
+{
+ struct mma7455l_info *mma = input_get_drvdata(inp);
+ if (mma->mode == MMA7455L_MODE_STANDBY)
+ update_mode(mma, MMA7455L_MODE_MEASUREMENT, mma->gSelect);
+
+ return 0;
+}
+
+static void mma7455l_input_close(struct input_dev *inp)
+{
+ struct mma7455l_info *mma = input_get_drvdata(inp);
+ update_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
+}
+
+static int __devinit mma7455l_probe(struct spi_device *spi)
+{
+ int rc;
+ struct mma7455l_info *mma;
+ struct mma7455l_platform_data *pdata = spi->dev.platform_data;
+ u_int8_t wai;
+
+ mma = kzalloc(sizeof(*mma), GFP_KERNEL);
+ if (!mma)
+ return -ENOMEM;
+
+ mutex_init(&mma->lock);
+ INIT_DELAYED_WORK(&mma->work, mma7455l_work);
+ mma->spi_dev = spi;
+ mma->flags = mma->working = 0;
+
+ spi_set_drvdata(spi, mma);
+
+ rc = spi_setup(spi);
+ if (rc < 0) {
+ printk(KERN_ERR
+ "mma7455l error durign spi_setup of mma7455l driver\n");
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(mma);
+ return rc;
+ }
+
+ wai = reg_read(mma, MMA7455L_REG_WHOAMI);
+ if (wai != MMA7455L_WHOAMI_MAGIC) {
+ printk(KERN_ERR
+ "mma7455l unknown whoami signature 0x%02x\n", wai);
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(mma);
+ return -ENODEV;
+ }
+
+ rc = request_irq(mma->spi_dev->irq, mma7455l_interrupt,
+ IRQF_TRIGGER_HIGH, "mma7455l", mma);
+ if (rc < 0) {
+ dev_err(&spi->dev, "mma7455l error requesting IRQ %d\n",
+ mma->spi_dev->irq);
+ /* FIXME */
+ return rc;
+ }
+
+ rc = sysfs_create_group(&spi->dev.kobj, &mma7455l_attr_group);
+ if (rc) {
+ dev_err(&spi->dev, "error creating sysfs group\n");
+ return rc;
+ }
+
+ /* initialize input layer details */
+ mma->input_dev = input_allocate_device();
+ if (!mma->input_dev) {
+ dev_err(&spi->dev,
+ "mma7455l Unable to allocate input device\n");
+ /* FIXME */
+ }
+
+ set_bit(EV_ABS, mma->input_dev->evbit);
+ set_bit(ABS_X, mma->input_dev->absbit);
+ set_bit(ABS_Y, mma->input_dev->absbit);
+ set_bit(ABS_Z, mma->input_dev->absbit);
+
+ input_set_drvdata(mma->input_dev, mma);
+ mma->input_dev->name = "MMA7455L";
+ mma->input_dev->open = mma7455l_input_open;
+ mma->input_dev->close = mma7455l_input_close;
+
+ rc = input_register_device(mma->input_dev);
+ if (!rc) {
+ update_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
+
+ mutex_lock(&mma->lock);
+ __reg_write_10(mma, MMA7455L_REG_XOFFL,
+ MMA7455L_REG_XOFFH, pdata->calibration_x);
+ __reg_write_10(mma, MMA7455L_REG_YOFFL,
+ MMA7455L_REG_YOFFH, pdata->calibration_y);
+ __reg_write_10(mma, MMA7455L_REG_ZOFFL,
+ MMA7455L_REG_ZOFFH, pdata->calibration_z);
+ mutex_unlock(&mma->lock);
+
+ return 0;
+ }
+
+ input_free_device(mma->input_dev);
+ return rc;
+}
+
+static int __devexit mma7455l_remove(struct spi_device *spi)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
+
+ sysfs_remove_group(&spi->dev.kobj, &mma7455l_attr_group);
+ input_unregister_device(mma->input_dev);
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(mma);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma7455l_suspend(struct spi_device *spi, pm_message_t
message)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
+ get_mode(mma, &mma->mode, &mma->gSelect);
+ set_mode(mma, MMA7455L_MODE_STANDBY, MMA7455L_GSELECT_2);
+
+ return 0;
+}
+
+static int mma7455l_resume(struct spi_device *spi)
+{
+ struct mma7455l_info *mma = dev_get_drvdata(&spi->dev);
+ update_mode(mma, mma->mode, mma->gSelect);
+
+ return 0;
+}
+#else
+#define mma7455l_suspend NULL
+#define mma7455l_resume  NULL
+#endif
+
+static struct spi_driver mma7455l_driver = {
+ .driver = {
+ .name = "mma7455l",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = mma7455l_probe,
+ .remove = __devexit_p(mma7455l_remove),
+ .suspend = mma7455l_suspend,
+ .resume = mma7455l_resume,
+};
+
+static int __init mma7455l_init(void)
+{
+ return spi_register_driver(&mma7455l_driver);
+}
+
+static void __exit mma7455l_exit(void)
+{
+ spi_unregister_driver(&mma7455l_driver);
+}
+
+MODULE_AUTHOR("Gregoire Gentil <gregoire@...til.com>");
+MODULE_LICENSE("GPL");
+
+module_init(mma7455l_init);
+module_exit(mma7455l_exit);
diff --git a/include/linux/mma7455l.h b/include/linux/mma7455l.h
new file mode 100644
index 0000000..12ab50a
--- /dev/null
+++ b/include/linux/mma7455l.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_MMA7455L_H
+#define _LINUX_MMA7455L_H
+
+struct mma7455l_platform_data {
+ /* Calibration offsets */
+ s16 calibration_x;
+ s16 calibration_y;
+ s16 calibration_z;
+};
+
+#endif /* _LINUX_MMA7455L_H */
-- 
1.6.0.4



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ