summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch')
-rwxr-xr-xtarget/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch781
1 files changed, 0 insertions, 781 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch b/target/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch
deleted file mode 100755
index ea1b231..0000000
--- a/target/linux/s3c24xx/patches-2.6.26/1031-lis302dl.patch.patch
+++ /dev/null
@@ -1,781 +0,0 @@
-From 65c5d85b4cf89969d2e2e981c018bf0ef1c03a2a Mon Sep 17 00:00:00 2001
-From: mokopatches <mokopatches@openmoko.org>
-Date: Wed, 16 Jul 2008 14:46:56 +0100
-Subject: [PATCH] lis302dl.patch
- This is a Linux driver for the STmicro LIS302DL 3-axis accelerometer.
-
-Signed-off-by: Harald Welte <laforge@openmoko.org>
----
- arch/arm/mach-s3c2440/mach-gta02.c | 46 +++-
- drivers/input/misc/Kconfig | 9 +
- drivers/input/misc/Makefile | 2 +
- drivers/input/misc/lis302dl.c | 633 ++++++++++++++++++++++++++++++++++++
- include/linux/lis302dl.h | 11 +
- 5 files changed, 700 insertions(+), 1 deletions(-)
- create mode 100644 drivers/input/misc/lis302dl.c
- create mode 100644 include/linux/lis302dl.h
-
-diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
-index f72a5ae..d11da10 100644
---- a/arch/arm/mach-s3c2440/mach-gta02.c
-+++ b/arch/arm/mach-s3c2440/mach-gta02.c
-@@ -46,6 +46,7 @@
- #include <linux/mtd/physmap.h>
-
- #include <linux/pcf50633.h>
-+#include <linux/lis302dl.h>
-
- #include <asm/mach/arch.h>
- #include <asm/mach/map.h>
-@@ -463,7 +464,7 @@ static struct s3c2410_ts_mach_info gta02_ts_cfg = {
- .oversampling_shift = 5,
- };
-
--/* SPI */
-+/* SPI: LCM control interface attached to Glamo3362 */
-
- static struct spi_board_info gta02_spi_board_info[] = {
- {
-@@ -504,6 +505,48 @@ static struct platform_device gta01_led_dev = {
- .resource = gta01_led_resources,
- };
-
-+/* SPI: Accelerometers attached to SPI of s3c244x */
-+
-+static void gta02_spi_acc_set_cs(struct s3c2410_spi_info *spi, int cs, int pol)
-+{
-+ s3c2410_gpio_setpin(cs, pol);
-+}
-+
-+static const struct lis302dl_platform_data lis302_pdata[] = {
-+ {
-+ .name = "lis302-1 (top)"
-+ }, {
-+ .name = "lis302-2 (bottom)"
-+ },
-+};
-+
-+static struct spi_board_info gta02_spi_acc_bdinfo[] = {
-+ {
-+ .modalias = "lis302dl",
-+ .platform_data = &lis302_pdata[0],
-+ .irq = GTA02_IRQ_GSENSOR_1,
-+ .max_speed_hz = 400 * 1000,
-+ .bus_num = 1,
-+ .chip_select = S3C2410_GPD12,
-+ .mode = SPI_MODE_3,
-+ },
-+ {
-+ .modalias = "lis302dl",
-+ .platform_data = &lis302_pdata[1],
-+ .irq = GTA02_IRQ_GSENSOR_2,
-+ .max_speed_hz = 400 * 1000,
-+ .bus_num = 1,
-+ .chip_select = S3C2410_GPD13,
-+ .mode = SPI_MODE_3,
-+ },
-+};
-+
-+static struct s3c2410_spi_info gta02_spi_acc_cfg = {
-+ .set_cs = gta02_spi_acc_set_cs,
-+ .board_size = ARRAY_SIZE(gta02_spi_acc_bdinfo),
-+ .board_info = gta02_spi_acc_bdinfo,
-+};
-+
- static struct resource gta02_led_resources[] = {
- {
- .name = "gta02-power:orange",
-@@ -746,6 +789,7 @@ static void __init gta02_machine_init(void)
- s3c_device_usb.dev.platform_data = &gta02_usb_info;
- s3c_device_nand.dev.platform_data = &gta02_nand_info;
- s3c_device_sdi.dev.platform_data = &gta02_mmc_cfg;
-+ s3c_device_spi1.dev.platform_data = &gta02_spi_acc_cfg;
-
- /* Only GTA02v1 has a SD_DETECT GPIO. Since the slot is not
- * hot-pluggable, this is not required anyway */
-diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
-index 432699d..ac8bcf4 100644
---- a/drivers/input/misc/Kconfig
-+++ b/drivers/input/misc/Kconfig
-@@ -197,4 +197,13 @@ config HP_SDC_RTC
- Say Y here if you want to support the built-in real time clock
- of the HP SDC controller.
-
-+config INPUT_LIS302DL
-+ tristate "STmicro LIS302DL 3-axis accelerometer"
-+ depends on SPI_MASTER
-+ help
-+ SPI driver for the STmicro LIS302DL 3-axis accelerometer.
-+
-+ The userspece 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 ebd39f2..0d223ba 100644
---- a/drivers/input/misc/Makefile
-+++ b/drivers/input/misc/Makefile
-@@ -20,3 +20,4 @@
- obj-$(CONFIG_INPUT_UINPUT) += uinput.o
- obj-$(CONFIG_INPUT_APANEL) += apanel.o
- obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o
-+obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
-diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
-new file mode 100644
-index 0000000..45c41c8
---- /dev/null
-+++ b/drivers/input/misc/lis302dl.c
-@@ -0,0 +1,633 @@
-+/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
-+ *
-+ * Copyright (C) 2007 by OpenMoko, Inc.
-+ * Author: Harald Welte <laforge@openmoko.org>
-+ * 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
-+ *
-+ * TODO
-+ * * statistics for overflow events
-+ * * configuration interface (sysfs) for
-+ * * enable/disable x/y/z axis data ready
-+ * * enable/disable resume from freee fall / click
-+ * * free fall / click parameters
-+ * * high pass filter parameters
-+ */
-+#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/lis302dl.h>
-+
-+#include <linux/spi/spi.h>
-+
-+#define LIS302DL_WHO_AM_I_MAGIC 0x3b
-+
-+enum lis302dl_reg {
-+ LIS302DL_REG_WHO_AM_I = 0x0f,
-+ LIS302DL_REG_CTRL1 = 0x20,
-+ LIS302DL_REG_CTRL2 = 0x21,
-+ LIS302DL_REG_CTRL3 = 0x22,
-+ LIS302DL_REG_HP_FILTER_RESET = 0x23,
-+ LIS302DL_REG_STATUS = 0x27,
-+ LIS302DL_REG_OUT_X = 0x29,
-+ LIS302DL_REG_OUT_Y = 0x2b,
-+ LIS302DL_REG_OUT_Z = 0x2d,
-+ LIS302DL_REG_FF_WU_CFG_1 = 0x30,
-+ LIS302DL_REG_FF_WU_SRC_1 = 0x31,
-+ LIS302DL_REG_FF_WU_THS_1 = 0x32,
-+ LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
-+ LIS302DL_REG_FF_WU_CFG_2 = 0x34,
-+ LIS302DL_REG_FF_WU_SRC_2 = 0x35,
-+ LIS302DL_REG_FF_WU_THS_2 = 0x36,
-+ LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
-+ LIS302DL_REG_CLICK_CFG = 0x38,
-+ LIS302DL_REG_CLICK_SRC = 0x39,
-+ LIS302DL_REG_CLICK_THSY_X = 0x3b,
-+ LIS302DL_REG_CLICK_THSZ = 0x3c,
-+ LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
-+ LIS302DL_REG_CLICK_LATENCY = 0x3e,
-+ LIS302DL_REG_CLICK_WINDOW = 0x3f,
-+};
-+
-+enum lis302dl_reg_ctrl1 {
-+ LIS302DL_CTRL1_Xen = 0x01,
-+ LIS302DL_CTRL1_Yen = 0x02,
-+ LIS302DL_CTRL1_Zen = 0x04,
-+ LIS302DL_CTRL1_STM = 0x08,
-+ LIS302DL_CTRL1_STP = 0x10,
-+ LIS302DL_CTRL1_FS = 0x20,
-+ LIS302DL_CTRL1_PD = 0x40,
-+ LIS302DL_CTRL1_DR = 0x80,
-+};
-+
-+enum lis302dl_reg_ctrl3 {
-+ LIS302DL_CTRL3_PP_OD = 0x40,
-+};
-+
-+enum lis302dl_reg_status {
-+ LIS302DL_STATUS_XDA = 0x01,
-+ LIS302DL_STATUS_YDA = 0x02,
-+ LIS302DL_STATUS_ZDA = 0x04,
-+ LIS302DL_STATUS_XYZDA = 0x08,
-+ LIS302DL_STATUS_XOR = 0x10,
-+ LIS302DL_STATUS_YOR = 0x20,
-+ LIS302DL_STATUS_ZOR = 0x40,
-+ LIS302DL_STATUS_XYZOR = 0x80,
-+};
-+
-+enum lis302dl_reg_ffwusrc1 {
-+ LIS302DL_FFWUSRC1_XL = 0x01,
-+ LIS302DL_FFWUSRC1_XH = 0x02,
-+ LIS302DL_FFWUSRC1_YL = 0x04,
-+ LIS302DL_FFWUSRC1_YH = 0x08,
-+ LIS302DL_FFWUSRC1_ZL = 0x10,
-+ LIS302DL_FFWUSRC1_ZH = 0x20,
-+ LIS302DL_FFWUSRC1_IA = 0x40,
-+};
-+
-+enum lis302dl_reg_cloik_src {
-+ LIS302DL_CLICKSRC_SINGLE_X = 0x01,
-+ LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
-+ LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
-+ LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
-+ LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
-+ LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
-+ LIS302DL_CLICKSRC_IA = 0x40,
-+};
-+
-+struct lis302dl_info {
-+ struct spi_device *spi_dev;
-+ struct input_dev *input_dev;
-+ struct mutex lock;
-+ struct work_struct work;
-+ unsigned int flags;
-+ unsigned int working;
-+ u_int8_t regs[0x40];
-+};
-+
-+#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */
-+#define LIS302DL_F_WUP_CLICK 0x0002
-+#define LIS302DL_F_POWER 0x0010
-+#define LIS302DL_F_FS 0x0020 /* ADC full scale */
-+
-+/* lowlevel register access functions */
-+
-+#define READ_BIT 0x01
-+#define MS_BIT 0x02
-+#define ADDR_SHIFT 2
-+
-+static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
-+{
-+ int rc;
-+ u_int8_t cmd;
-+
-+ cmd = (reg << ADDR_SHIFT) | READ_BIT;
-+
-+ rc = spi_w8r8(lis->spi_dev, cmd);
-+
-+ return rc;
-+}
-+
-+static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
-+{
-+ u_int8_t ret;
-+
-+ mutex_lock(&lis->lock);
-+ ret = __reg_read(lis, reg);
-+ mutex_unlock(&lis->lock);
-+
-+ return ret;
-+}
-+
-+static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
-+{
-+ u_int8_t buf[2];
-+
-+ buf[0] = (reg << ADDR_SHIFT);
-+ buf[1] = val;
-+
-+ return spi_write(lis->spi_dev, buf, sizeof(buf));
-+}
-+
-+static int reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
-+{
-+ int ret;
-+
-+ mutex_lock(&lis->lock);
-+ ret = __reg_write(lis, reg, val);
-+ mutex_unlock(&lis->lock);
-+
-+ return ret;
-+}
-+
-+static int reg_set_bit_mask(struct lis302dl_info *lis,
-+ u_int8_t reg, u_int8_t mask, u_int8_t val)
-+{
-+ int ret;
-+ u_int8_t tmp;
-+
-+ val &= mask;
-+
-+ mutex_lock(&lis->lock);
-+
-+ tmp = __reg_read(lis, reg);
-+ tmp &= ~mask;
-+ tmp |= val;
-+ ret = __reg_write(lis, reg, tmp);
-+
-+ mutex_unlock(&lis->lock);
-+
-+ return ret;
-+}
-+
-+/* interrupt handling related */
-+
-+enum lis302dl_intmode {
-+ LIS302DL_INTMODE_GND = 0x00,
-+ LIS302DL_INTMODE_FF_WU_1 = 0x01,
-+ LIX302DL_INTMODE_FF_WU_2 = 0x02,
-+ LIX302DL_INTMODE_FF_WU_12 = 0x03,
-+ LIX302DL_INTMODE_DATA_READY = 0x04,
-+ LIX302DL_INTMODE_CLICK = 0x07,
-+};
-+
-+static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
-+ enum lis302dl_intmode mode)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+
-+ if (int_pin == 1)
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
-+ else if (int_pin == 2)
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
-+}
-+
-+static void _report_btn_single(struct input_dev *inp, int btn)
-+{
-+ input_report_key(inp, btn, 1);
-+ input_sync(inp);
-+ input_report_key(inp, btn, 0);
-+}
-+
-+static void _report_btn_double(struct input_dev *inp, int btn)
-+{
-+ input_report_key(inp, btn, 1);
-+ input_sync(inp);
-+ input_report_key(inp, btn, 0);
-+ input_sync(inp);
-+ input_report_key(inp, btn, 1);
-+ input_sync(inp);
-+ input_report_key(inp, btn, 0);
-+}
-+
-+static void lis302dl_work(struct work_struct *work)
-+{
-+ struct lis302dl_info *lis =
-+ container_of(work, struct lis302dl_info, work);
-+
-+ u_int8_t status, ff_wu_src_1, click_src;
-+ u_int8_t val;
-+
-+ lis->working = 1;
-+
-+ status = reg_read(lis, LIS302DL_REG_STATUS);
-+ ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
-+ click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
-+
-+ if (status & LIS302DL_STATUS_XDA) {
-+ val = reg_read(lis, LIS302DL_REG_OUT_X);
-+ if (lis->flags & LIS302DL_F_FS)
-+ val = val << 2;
-+ input_report_rel(lis->input_dev, REL_X, val);
-+ }
-+
-+ if (status & LIS302DL_STATUS_YDA) {
-+ val = reg_read(lis, LIS302DL_REG_OUT_Y);
-+ if (lis->flags & LIS302DL_F_FS)
-+ val = val << 2;
-+ input_report_rel(lis->input_dev, REL_Y, val);
-+ }
-+
-+ if (status & LIS302DL_STATUS_ZDA) {
-+ val = reg_read(lis, LIS302DL_REG_OUT_Z);
-+ if (lis->flags & LIS302DL_F_FS)
-+ val = val << 2;
-+ input_report_rel(lis->input_dev, REL_Z, val);
-+ }
-+
-+ if (status & 0xf0)
-+ dev_dbg(&lis->spi_dev->dev, "overrun!\n");
-+
-+ /* FIXME: implement overrun statistics */
-+
-+ if (ff_wu_src_1 & LIS302DL_FFWUSRC1_IA) {
-+ /* FIXME: free fall interrupt handling */
-+ }
-+
-+ if (click_src & LIS302DL_CLICKSRC_IA) {
-+ if (click_src & LIS302DL_CLICKSRC_SINGLE_X)
-+ _report_btn_single(lis->input_dev, BTN_X);
-+ if (click_src & LIS302DL_CLICKSRC_DOUBLE_X)
-+ _report_btn_double(lis->input_dev, BTN_X);
-+
-+ if (click_src & LIS302DL_CLICKSRC_SINGLE_Y)
-+ _report_btn_single(lis->input_dev, BTN_Y);
-+ if (click_src & LIS302DL_CLICKSRC_DOUBLE_Y)
-+ _report_btn_double(lis->input_dev, BTN_Y);
-+
-+ if (click_src & LIS302DL_CLICKSRC_SINGLE_Z)
-+ _report_btn_single(lis->input_dev, BTN_Z);
-+ if (click_src & LIS302DL_CLICKSRC_DOUBLE_Z)
-+ _report_btn_double(lis->input_dev, BTN_Z);
-+ }
-+
-+ lis->working = 0;
-+ input_sync(lis->input_dev);
-+ put_device(&lis->spi_dev->dev);
-+
-+ enable_irq(lis->spi_dev->irq);
-+}
-+
-+static void lis302dl_schedule_work(struct lis302dl_info *lis)
-+{
-+ int status;
-+
-+ get_device(&lis->spi_dev->dev);
-+ status = schedule_work(&lis->work);
-+ if (!status && !lis->working)
-+ dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
-+}
-+
-+static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
-+{
-+ struct lis302dl_info *lis = _lis;
-+
-+ lis302dl_schedule_work(lis);
-+
-+ /* Disable any further interrupts until we have processed
-+ * the current one */
-+ disable_irq(lis->spi_dev->irq);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/* sysfs */
-+
-+static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
-+
-+ return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
-+}
-+
-+static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ if (!strcmp(buf, "400\n"))
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
-+ LIS302DL_CTRL1_DR);
-+ else
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, 0);
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
-+
-+static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
-+
-+ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
-+}
-+
-+static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ if (!strcmp(buf, "9.2\n"))
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
-+ LIS302DL_CTRL1_FS);
-+ else
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, 0);
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
-+
-+static struct attribute *lis302dl_sysfs_entries[] = {
-+ &dev_attr_sample_rate.attr,
-+ &dev_attr_full_scale.attr,
-+};
-+
-+static struct attribute_group lis302dl_attr_group = {
-+ .name = NULL,
-+ .attrs = lis302dl_sysfs_entries,
-+};
-+
-+/* input device handling and driver core interaction */
-+
-+static int lis302dl_input_open(struct input_dev *inp)
-+{
-+ struct lis302dl_info *lis = inp->private;
-+ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
-+ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
-+
-+ /* make sure we're powered up and generate data ready */
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
-+
-+ return 0;
-+}
-+
-+static void lis302dl_input_close(struct input_dev *inp)
-+{
-+ struct lis302dl_info *lis = inp->private;
-+ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
-+ LIS302DL_CTRL1_Zen;
-+
-+ /* since the input core already serializes access and makes sure we
-+ * only see close() for the close of the lastre user, we can safely
-+ * disable the data ready events */
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
-+
-+ /* however, don't power down the whole device if still needed */
-+ if (!(lis->flags & LIS302DL_F_WUP_FF ||
-+ lis->flags & LIS302DL_F_WUP_CLICK)) {
-+ reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
-+ 0x00);
-+ }
-+}
-+
-+static int __devinit lis302dl_probe(struct spi_device *spi)
-+{
-+ int rc;
-+ struct lis302dl_info *lis;
-+ u_int8_t wai;
-+
-+ lis = kzalloc(sizeof(*lis), GFP_KERNEL);
-+ if (!lis)
-+ return -ENOMEM;
-+
-+ mutex_init(&lis->lock);
-+ INIT_WORK(&lis->work, lis302dl_work);
-+ lis->spi_dev = spi;
-+
-+ spi_set_drvdata(spi, lis);
-+
-+ rc = spi_setup(spi);
-+ if (rc < 0) {
-+ printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
-+ dev_set_drvdata(&spi->dev, NULL);
-+ kfree(lis);
-+ return rc;
-+ }
-+
-+ wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
-+ if (wai != LIS302DL_WHO_AM_I_MAGIC) {
-+ printk(KERN_ERR "unknown who_am_i signature 0x%02x\n", wai);
-+ dev_set_drvdata(&spi->dev, NULL);
-+ kfree(lis);
-+ return -ENODEV;
-+ }
-+
-+ /* switch interrupt to open collector */
-+ reg_write(lis, LIS302DL_CTRL3_PP_OD, 0x7c);
-+
-+ rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt, IRQF_DISABLED,
-+ "lis302dl", NULL);
-+ if (rc < 0) {
-+ dev_err(&spi->dev, "error requesting IRQ %d\n",
-+ lis->spi_dev->irq);
-+ /* FIXME */
-+ return rc;
-+ }
-+
-+ rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
-+ if (rc) {
-+ dev_err(&spi->dev, "error creating sysfs group\n");
-+ /* FIXME */
-+ return rc;
-+ }
-+
-+ /* initialize input layer details */
-+ lis->input_dev = input_allocate_device();
-+ if (!lis->input_dev) {
-+ dev_err(&spi->dev, "Unable to allocate input device\n");
-+ /* FIXME */
-+ }
-+
-+ set_bit(EV_REL, lis->input_dev->evbit);
-+ set_bit(EV_KEY, lis->input_dev->evbit);
-+ set_bit(BTN_X, lis->input_dev->keybit);
-+ set_bit(BTN_Y, lis->input_dev->keybit);
-+ set_bit(BTN_Z, lis->input_dev->keybit);
-+
-+ lis->input_dev->private = lis;
-+ lis->input_dev->name = "lis302dl"; /* FIXME: platform data */
-+ lis->input_dev->id.bustype = BUS_I2C; /* FIXME: SPI Bus */
-+ lis->input_dev->open = lis302dl_input_open;
-+ lis->input_dev->close = lis302dl_input_close;
-+
-+ input_register_device(lis->input_dev);
-+
-+ return 0;
-+}
-+
-+static int __devexit lis302dl_remove(struct spi_device *spi)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+
-+ /* power down the device */
-+ reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
-+ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
-+ input_unregister_device(lis->input_dev);
-+ dev_set_drvdata(&spi->dev, NULL);
-+ kfree(lis);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+
-+ /* save registers */
-+ lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
-+ lis->regs[LIS302DL_REG_CTRL2] = reg_read(lis, LIS302DL_REG_CTRL2);
-+ lis->regs[LIS302DL_REG_CTRL3] = reg_read(lis, LIS302DL_REG_CTRL3);
-+ lis->regs[LIS302DL_REG_FF_WU_CFG_1] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_CFG_1);
-+ lis->regs[LIS302DL_REG_FF_WU_THS_1] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_THS_1);
-+ lis->regs[LIS302DL_REG_FF_WU_DURATION_1] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_DURATION_1);
-+ lis->regs[LIS302DL_REG_FF_WU_CFG_2] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_CFG_2);
-+ lis->regs[LIS302DL_REG_FF_WU_THS_2] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_THS_2);
-+ lis->regs[LIS302DL_REG_FF_WU_DURATION_2] =
-+ reg_read(lis, LIS302DL_REG_FF_WU_DURATION_2);
-+ lis->regs[LIS302DL_REG_CLICK_CFG] =
-+ reg_read(lis, LIS302DL_REG_CLICK_CFG);
-+ lis->regs[LIS302DL_REG_CLICK_THSY_X] =
-+ reg_read(lis, LIS302DL_REG_CLICK_THSY_X);
-+ lis->regs[LIS302DL_REG_CLICK_THSZ] =
-+ reg_read(lis, LIS302DL_REG_CLICK_THSZ);
-+ lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT] =
-+ reg_read(lis, LIS302DL_REG_CLICK_TIME_LIMIT);
-+ lis->regs[LIS302DL_REG_CLICK_LATENCY] =
-+ reg_read(lis, LIS302DL_REG_CLICK_LATENCY);
-+ lis->regs[LIS302DL_REG_CLICK_WINDOW] =
-+ reg_read(lis, LIS302DL_REG_CLICK_WINDOW);
-+
-+ /* determine if we want to wake up from the accel. */
-+ if (!(lis->flags & LIS302DL_F_WUP_FF ||
-+ lis->flags & LIS302DL_F_WUP_CLICK)) {
-+ /* power down */
-+ u_int8_t tmp;
-+ tmp = reg_read(lis, LIS302DL_REG_CTRL1);
-+ tmp &= ~LIS302DL_CTRL1_PD;
-+ reg_write(lis, LIS302DL_REG_CTRL1, tmp);
-+ }
-+
-+ return 0;
-+}
-+
-+static int lis302dl_resume(struct spi_device *spi)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+
-+ /* restore registers after resume */
-+ reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
-+ reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
-+ reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
-+ lis->regs[LIS302DL_REG_FF_WU_CFG_1]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
-+ lis->regs[LIS302DL_REG_FF_WU_THS_1]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
-+ lis->regs[LIS302DL_REG_FF_WU_DURATION_1]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_CFG_2,
-+ lis->regs[LIS302DL_REG_FF_WU_CFG_2]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_THS_2,
-+ lis->regs[LIS302DL_REG_FF_WU_THS_2]);
-+ reg_write(lis, LIS302DL_REG_FF_WU_DURATION_2,
-+ lis->regs[LIS302DL_REG_FF_WU_DURATION_2]);
-+ reg_write(lis, LIS302DL_REG_CLICK_CFG,
-+ lis->regs[LIS302DL_REG_CLICK_CFG]);
-+ reg_write(lis, LIS302DL_REG_CLICK_THSY_X,
-+ lis->regs[LIS302DL_REG_CLICK_THSY_X]);
-+ reg_write(lis, LIS302DL_REG_CLICK_THSZ,
-+ lis->regs[LIS302DL_REG_CLICK_THSZ]);
-+ reg_write(lis, LIS302DL_REG_CLICK_TIME_LIMIT,
-+ lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT]);
-+ reg_write(lis, LIS302DL_REG_CLICK_LATENCY,
-+ lis->regs[LIS302DL_REG_CLICK_LATENCY]);
-+ reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
-+ lis->regs[LIS302DL_REG_CLICK_WINDOW]);
-+
-+ return 0;
-+}
-+#else
-+#define lis302dl_suspend NULL
-+#define lis302dl_resume NULL
-+#endif
-+
-+static struct spi_driver lis302dl_driver = {
-+ .driver = {
-+ .name = "lis302dl",
-+ .owner = THIS_MODULE,
-+ },
-+
-+ .probe = lis302dl_probe,
-+ .remove = __devexit_p(lis302dl_remove),
-+ .suspend = lis302dl_suspend,
-+ .resume = lis302dl_resume,
-+};
-+
-+static int __init lis302dl_init(void)
-+{
-+ return spi_register_driver(&lis302dl_driver);
-+}
-+
-+static void __exit lis302dl_exit(void)
-+{
-+ spi_unregister_driver(&lis302dl_driver);
-+}
-+
-+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
-+MODULE_LICENSE("GPL");
-+
-+module_init(lis302dl_init);
-+module_exit(lis302dl_exit);
-diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
-new file mode 100644
-index 0000000..d0f31be
---- /dev/null
-+++ b/include/linux/lis302dl.h
-@@ -0,0 +1,11 @@
-+#ifndef _LINUX_LIS302DL_H
-+#define _LINUX_LIS302DL_H
-+
-+#include <linux/types.h>
-+
-+struct lis302dl_platform_data {
-+ char *name;
-+};
-+
-+#endif /* _LINUX_LIS302DL_H */
-+
---
-1.5.6.3
-