1 From 65c5d85b4cf89969d2e2e981c018bf0ef1c03a2a Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Wed, 16 Jul 2008 14:46:56 +0100
4 Subject: [PATCH] lis302dl.patch
5 This is a Linux driver for the STmicro LIS302DL 3-axis accelerometer.
7 Signed-off-by: Harald Welte <laforge@openmoko.org>
9 arch/arm/mach-s3c2440/mach-gta02.c | 46 +++-
10 drivers/input/misc/Kconfig | 9 +
11 drivers/input/misc/Makefile | 2 +
12 drivers/input/misc/lis302dl.c | 633 ++++++++++++++++++++++++++++++++++++
13 include/linux/lis302dl.h | 11 +
14 5 files changed, 700 insertions(+), 1 deletions(-)
15 create mode 100644 drivers/input/misc/lis302dl.c
16 create mode 100644 include/linux/lis302dl.h
18 diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
19 index f72a5ae..d11da10 100644
20 --- a/arch/arm/mach-s3c2440/mach-gta02.c
21 +++ b/arch/arm/mach-s3c2440/mach-gta02.c
23 #include <linux/mtd/physmap.h>
25 #include <linux/pcf50633.h>
26 +#include <linux/lis302dl.h>
28 #include <asm/mach/arch.h>
29 #include <asm/mach/map.h>
30 @@ -463,7 +464,7 @@ static struct s3c2410_ts_mach_info gta02_ts_cfg = {
31 .oversampling_shift = 5,
35 +/* SPI: LCM control interface attached to Glamo3362 */
37 static struct spi_board_info gta02_spi_board_info[] = {
39 @@ -504,6 +505,48 @@ static struct platform_device gta01_led_dev = {
40 .resource = gta01_led_resources,
43 +/* SPI: Accelerometers attached to SPI of s3c244x */
45 +static void gta02_spi_acc_set_cs(struct s3c2410_spi_info *spi, int cs, int pol)
47 + s3c2410_gpio_setpin(cs, pol);
50 +static const struct lis302dl_platform_data lis302_pdata[] = {
52 + .name = "lis302-1 (top)"
54 + .name = "lis302-2 (bottom)"
58 +static struct spi_board_info gta02_spi_acc_bdinfo[] = {
60 + .modalias = "lis302dl",
61 + .platform_data = &lis302_pdata[0],
62 + .irq = GTA02_IRQ_GSENSOR_1,
63 + .max_speed_hz = 400 * 1000,
65 + .chip_select = S3C2410_GPD12,
69 + .modalias = "lis302dl",
70 + .platform_data = &lis302_pdata[1],
71 + .irq = GTA02_IRQ_GSENSOR_2,
72 + .max_speed_hz = 400 * 1000,
74 + .chip_select = S3C2410_GPD13,
79 +static struct s3c2410_spi_info gta02_spi_acc_cfg = {
80 + .set_cs = gta02_spi_acc_set_cs,
81 + .board_size = ARRAY_SIZE(gta02_spi_acc_bdinfo),
82 + .board_info = gta02_spi_acc_bdinfo,
85 static struct resource gta02_led_resources[] = {
87 .name = "gta02-power:orange",
88 @@ -746,6 +789,7 @@ static void __init gta02_machine_init(void)
89 s3c_device_usb.dev.platform_data = >a02_usb_info;
90 s3c_device_nand.dev.platform_data = >a02_nand_info;
91 s3c_device_sdi.dev.platform_data = >a02_mmc_cfg;
92 + s3c_device_spi1.dev.platform_data = >a02_spi_acc_cfg;
94 /* Only GTA02v1 has a SD_DETECT GPIO. Since the slot is not
95 * hot-pluggable, this is not required anyway */
96 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
97 index 432699d..ac8bcf4 100644
98 --- a/drivers/input/misc/Kconfig
99 +++ b/drivers/input/misc/Kconfig
100 @@ -197,4 +197,13 @@ config HP_SDC_RTC
101 Say Y here if you want to support the built-in real time clock
102 of the HP SDC controller.
104 +config INPUT_LIS302DL
105 + tristate "STmicro LIS302DL 3-axis accelerometer"
106 + depends on SPI_MASTER
108 + SPI driver for the STmicro LIS302DL 3-axis accelerometer.
110 + The userspece interface is a 3-axis (X/Y/Z) relative movement
111 + Linux input device, reporting REL_[XYZ] events.
114 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
115 index ebd39f2..0d223ba 100644
116 --- a/drivers/input/misc/Makefile
117 +++ b/drivers/input/misc/Makefile
119 obj-$(CONFIG_INPUT_UINPUT) += uinput.o
120 obj-$(CONFIG_INPUT_APANEL) += apanel.o
121 obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o
122 +obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
123 diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
125 index 0000000..45c41c8
127 +++ b/drivers/input/misc/lis302dl.c
129 +/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
131 + * Copyright (C) 2007 by OpenMoko, Inc.
132 + * Author: Harald Welte <laforge@openmoko.org>
133 + * All rights reserved.
135 + * This program is free software; you can redistribute it and/or
136 + * modify it under the terms of the GNU General Public License as
137 + * published by the Free Software Foundation; either version 2 of
138 + * the License, or (at your option) any later version.
140 + * This program is distributed in the hope that it will be useful,
141 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
142 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143 + * GNU General Public License for more details.
145 + * You should have received a copy of the GNU General Public License
146 + * along with this program; if not, write to the Free Software
147 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
148 + * MA 02111-1307 USA
151 + * * statistics for overflow events
152 + * * configuration interface (sysfs) for
153 + * * enable/disable x/y/z axis data ready
154 + * * enable/disable resume from freee fall / click
155 + * * free fall / click parameters
156 + * * high pass filter parameters
158 +#include <linux/kernel.h>
159 +#include <linux/types.h>
160 +#include <linux/module.h>
161 +#include <linux/device.h>
162 +#include <linux/platform_device.h>
163 +#include <linux/delay.h>
164 +#include <linux/input.h>
165 +#include <linux/irq.h>
166 +#include <linux/interrupt.h>
167 +#include <linux/sysfs.h>
169 +#include <linux/lis302dl.h>
171 +#include <linux/spi/spi.h>
173 +#define LIS302DL_WHO_AM_I_MAGIC 0x3b
176 + LIS302DL_REG_WHO_AM_I = 0x0f,
177 + LIS302DL_REG_CTRL1 = 0x20,
178 + LIS302DL_REG_CTRL2 = 0x21,
179 + LIS302DL_REG_CTRL3 = 0x22,
180 + LIS302DL_REG_HP_FILTER_RESET = 0x23,
181 + LIS302DL_REG_STATUS = 0x27,
182 + LIS302DL_REG_OUT_X = 0x29,
183 + LIS302DL_REG_OUT_Y = 0x2b,
184 + LIS302DL_REG_OUT_Z = 0x2d,
185 + LIS302DL_REG_FF_WU_CFG_1 = 0x30,
186 + LIS302DL_REG_FF_WU_SRC_1 = 0x31,
187 + LIS302DL_REG_FF_WU_THS_1 = 0x32,
188 + LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
189 + LIS302DL_REG_FF_WU_CFG_2 = 0x34,
190 + LIS302DL_REG_FF_WU_SRC_2 = 0x35,
191 + LIS302DL_REG_FF_WU_THS_2 = 0x36,
192 + LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
193 + LIS302DL_REG_CLICK_CFG = 0x38,
194 + LIS302DL_REG_CLICK_SRC = 0x39,
195 + LIS302DL_REG_CLICK_THSY_X = 0x3b,
196 + LIS302DL_REG_CLICK_THSZ = 0x3c,
197 + LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
198 + LIS302DL_REG_CLICK_LATENCY = 0x3e,
199 + LIS302DL_REG_CLICK_WINDOW = 0x3f,
202 +enum lis302dl_reg_ctrl1 {
203 + LIS302DL_CTRL1_Xen = 0x01,
204 + LIS302DL_CTRL1_Yen = 0x02,
205 + LIS302DL_CTRL1_Zen = 0x04,
206 + LIS302DL_CTRL1_STM = 0x08,
207 + LIS302DL_CTRL1_STP = 0x10,
208 + LIS302DL_CTRL1_FS = 0x20,
209 + LIS302DL_CTRL1_PD = 0x40,
210 + LIS302DL_CTRL1_DR = 0x80,
213 +enum lis302dl_reg_ctrl3 {
214 + LIS302DL_CTRL3_PP_OD = 0x40,
217 +enum lis302dl_reg_status {
218 + LIS302DL_STATUS_XDA = 0x01,
219 + LIS302DL_STATUS_YDA = 0x02,
220 + LIS302DL_STATUS_ZDA = 0x04,
221 + LIS302DL_STATUS_XYZDA = 0x08,
222 + LIS302DL_STATUS_XOR = 0x10,
223 + LIS302DL_STATUS_YOR = 0x20,
224 + LIS302DL_STATUS_ZOR = 0x40,
225 + LIS302DL_STATUS_XYZOR = 0x80,
228 +enum lis302dl_reg_ffwusrc1 {
229 + LIS302DL_FFWUSRC1_XL = 0x01,
230 + LIS302DL_FFWUSRC1_XH = 0x02,
231 + LIS302DL_FFWUSRC1_YL = 0x04,
232 + LIS302DL_FFWUSRC1_YH = 0x08,
233 + LIS302DL_FFWUSRC1_ZL = 0x10,
234 + LIS302DL_FFWUSRC1_ZH = 0x20,
235 + LIS302DL_FFWUSRC1_IA = 0x40,
238 +enum lis302dl_reg_cloik_src {
239 + LIS302DL_CLICKSRC_SINGLE_X = 0x01,
240 + LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
241 + LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
242 + LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
243 + LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
244 + LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
245 + LIS302DL_CLICKSRC_IA = 0x40,
248 +struct lis302dl_info {
249 + struct spi_device *spi_dev;
250 + struct input_dev *input_dev;
252 + struct work_struct work;
253 + unsigned int flags;
254 + unsigned int working;
255 + u_int8_t regs[0x40];
258 +#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */
259 +#define LIS302DL_F_WUP_CLICK 0x0002
260 +#define LIS302DL_F_POWER 0x0010
261 +#define LIS302DL_F_FS 0x0020 /* ADC full scale */
263 +/* lowlevel register access functions */
265 +#define READ_BIT 0x01
267 +#define ADDR_SHIFT 2
269 +static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
274 + cmd = (reg << ADDR_SHIFT) | READ_BIT;
276 + rc = spi_w8r8(lis->spi_dev, cmd);
281 +static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
285 + mutex_lock(&lis->lock);
286 + ret = __reg_read(lis, reg);
287 + mutex_unlock(&lis->lock);
292 +static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
296 + buf[0] = (reg << ADDR_SHIFT);
299 + return spi_write(lis->spi_dev, buf, sizeof(buf));
302 +static int reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
306 + mutex_lock(&lis->lock);
307 + ret = __reg_write(lis, reg, val);
308 + mutex_unlock(&lis->lock);
313 +static int reg_set_bit_mask(struct lis302dl_info *lis,
314 + u_int8_t reg, u_int8_t mask, u_int8_t val)
321 + mutex_lock(&lis->lock);
323 + tmp = __reg_read(lis, reg);
326 + ret = __reg_write(lis, reg, tmp);
328 + mutex_unlock(&lis->lock);
333 +/* interrupt handling related */
335 +enum lis302dl_intmode {
336 + LIS302DL_INTMODE_GND = 0x00,
337 + LIS302DL_INTMODE_FF_WU_1 = 0x01,
338 + LIX302DL_INTMODE_FF_WU_2 = 0x02,
339 + LIX302DL_INTMODE_FF_WU_12 = 0x03,
340 + LIX302DL_INTMODE_DATA_READY = 0x04,
341 + LIX302DL_INTMODE_CLICK = 0x07,
344 +static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
345 + enum lis302dl_intmode mode)
347 + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
350 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
351 + else if (int_pin == 2)
352 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
355 +static void _report_btn_single(struct input_dev *inp, int btn)
357 + input_report_key(inp, btn, 1);
359 + input_report_key(inp, btn, 0);
362 +static void _report_btn_double(struct input_dev *inp, int btn)
364 + input_report_key(inp, btn, 1);
366 + input_report_key(inp, btn, 0);
368 + input_report_key(inp, btn, 1);
370 + input_report_key(inp, btn, 0);
373 +static void lis302dl_work(struct work_struct *work)
375 + struct lis302dl_info *lis =
376 + container_of(work, struct lis302dl_info, work);
378 + u_int8_t status, ff_wu_src_1, click_src;
383 + status = reg_read(lis, LIS302DL_REG_STATUS);
384 + ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
385 + click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
387 + if (status & LIS302DL_STATUS_XDA) {
388 + val = reg_read(lis, LIS302DL_REG_OUT_X);
389 + if (lis->flags & LIS302DL_F_FS)
391 + input_report_rel(lis->input_dev, REL_X, val);
394 + if (status & LIS302DL_STATUS_YDA) {
395 + val = reg_read(lis, LIS302DL_REG_OUT_Y);
396 + if (lis->flags & LIS302DL_F_FS)
398 + input_report_rel(lis->input_dev, REL_Y, val);
401 + if (status & LIS302DL_STATUS_ZDA) {
402 + val = reg_read(lis, LIS302DL_REG_OUT_Z);
403 + if (lis->flags & LIS302DL_F_FS)
405 + input_report_rel(lis->input_dev, REL_Z, val);
409 + dev_dbg(&lis->spi_dev->dev, "overrun!\n");
411 + /* FIXME: implement overrun statistics */
413 + if (ff_wu_src_1 & LIS302DL_FFWUSRC1_IA) {
414 + /* FIXME: free fall interrupt handling */
417 + if (click_src & LIS302DL_CLICKSRC_IA) {
418 + if (click_src & LIS302DL_CLICKSRC_SINGLE_X)
419 + _report_btn_single(lis->input_dev, BTN_X);
420 + if (click_src & LIS302DL_CLICKSRC_DOUBLE_X)
421 + _report_btn_double(lis->input_dev, BTN_X);
423 + if (click_src & LIS302DL_CLICKSRC_SINGLE_Y)
424 + _report_btn_single(lis->input_dev, BTN_Y);
425 + if (click_src & LIS302DL_CLICKSRC_DOUBLE_Y)
426 + _report_btn_double(lis->input_dev, BTN_Y);
428 + if (click_src & LIS302DL_CLICKSRC_SINGLE_Z)
429 + _report_btn_single(lis->input_dev, BTN_Z);
430 + if (click_src & LIS302DL_CLICKSRC_DOUBLE_Z)
431 + _report_btn_double(lis->input_dev, BTN_Z);
435 + input_sync(lis->input_dev);
436 + put_device(&lis->spi_dev->dev);
438 + enable_irq(lis->spi_dev->irq);
441 +static void lis302dl_schedule_work(struct lis302dl_info *lis)
445 + get_device(&lis->spi_dev->dev);
446 + status = schedule_work(&lis->work);
447 + if (!status && !lis->working)
448 + dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
451 +static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
453 + struct lis302dl_info *lis = _lis;
455 + lis302dl_schedule_work(lis);
457 + /* Disable any further interrupts until we have processed
458 + * the current one */
459 + disable_irq(lis->spi_dev->irq);
461 + return IRQ_HANDLED;
466 +static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
469 + struct lis302dl_info *lis = dev_get_drvdata(dev);
470 + u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
472 + return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
475 +static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
476 + const char *buf, size_t count)
478 + struct lis302dl_info *lis = dev_get_drvdata(dev);
480 + if (!strcmp(buf, "400\n"))
481 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
482 + LIS302DL_CTRL1_DR);
484 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, 0);
489 +static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
491 +static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
494 + struct lis302dl_info *lis = dev_get_drvdata(dev);
495 + u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
497 + return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
500 +static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
501 + const char *buf, size_t count)
503 + struct lis302dl_info *lis = dev_get_drvdata(dev);
505 + if (!strcmp(buf, "9.2\n"))
506 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
507 + LIS302DL_CTRL1_FS);
509 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, 0);
514 +static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
516 +static struct attribute *lis302dl_sysfs_entries[] = {
517 + &dev_attr_sample_rate.attr,
518 + &dev_attr_full_scale.attr,
521 +static struct attribute_group lis302dl_attr_group = {
523 + .attrs = lis302dl_sysfs_entries,
526 +/* input device handling and driver core interaction */
528 +static int lis302dl_input_open(struct input_dev *inp)
530 + struct lis302dl_info *lis = inp->private;
531 + u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
532 + LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
534 + /* make sure we're powered up and generate data ready */
535 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
540 +static void lis302dl_input_close(struct input_dev *inp)
542 + struct lis302dl_info *lis = inp->private;
543 + u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
544 + LIS302DL_CTRL1_Zen;
546 + /* since the input core already serializes access and makes sure we
547 + * only see close() for the close of the lastre user, we can safely
548 + * disable the data ready events */
549 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
551 + /* however, don't power down the whole device if still needed */
552 + if (!(lis->flags & LIS302DL_F_WUP_FF ||
553 + lis->flags & LIS302DL_F_WUP_CLICK)) {
554 + reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
559 +static int __devinit lis302dl_probe(struct spi_device *spi)
562 + struct lis302dl_info *lis;
565 + lis = kzalloc(sizeof(*lis), GFP_KERNEL);
569 + mutex_init(&lis->lock);
570 + INIT_WORK(&lis->work, lis302dl_work);
571 + lis->spi_dev = spi;
573 + spi_set_drvdata(spi, lis);
575 + rc = spi_setup(spi);
577 + printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
578 + dev_set_drvdata(&spi->dev, NULL);
583 + wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
584 + if (wai != LIS302DL_WHO_AM_I_MAGIC) {
585 + printk(KERN_ERR "unknown who_am_i signature 0x%02x\n", wai);
586 + dev_set_drvdata(&spi->dev, NULL);
591 + /* switch interrupt to open collector */
592 + reg_write(lis, LIS302DL_CTRL3_PP_OD, 0x7c);
594 + rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt, IRQF_DISABLED,
597 + dev_err(&spi->dev, "error requesting IRQ %d\n",
598 + lis->spi_dev->irq);
603 + rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
605 + dev_err(&spi->dev, "error creating sysfs group\n");
610 + /* initialize input layer details */
611 + lis->input_dev = input_allocate_device();
612 + if (!lis->input_dev) {
613 + dev_err(&spi->dev, "Unable to allocate input device\n");
617 + set_bit(EV_REL, lis->input_dev->evbit);
618 + set_bit(EV_KEY, lis->input_dev->evbit);
619 + set_bit(BTN_X, lis->input_dev->keybit);
620 + set_bit(BTN_Y, lis->input_dev->keybit);
621 + set_bit(BTN_Z, lis->input_dev->keybit);
623 + lis->input_dev->private = lis;
624 + lis->input_dev->name = "lis302dl"; /* FIXME: platform data */
625 + lis->input_dev->id.bustype = BUS_I2C; /* FIXME: SPI Bus */
626 + lis->input_dev->open = lis302dl_input_open;
627 + lis->input_dev->close = lis302dl_input_close;
629 + input_register_device(lis->input_dev);
634 +static int __devexit lis302dl_remove(struct spi_device *spi)
636 + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
638 + /* power down the device */
639 + reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
640 + sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
641 + input_unregister_device(lis->input_dev);
642 + dev_set_drvdata(&spi->dev, NULL);
649 +static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
651 + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
653 + /* save registers */
654 + lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
655 + lis->regs[LIS302DL_REG_CTRL2] = reg_read(lis, LIS302DL_REG_CTRL2);
656 + lis->regs[LIS302DL_REG_CTRL3] = reg_read(lis, LIS302DL_REG_CTRL3);
657 + lis->regs[LIS302DL_REG_FF_WU_CFG_1] =
658 + reg_read(lis, LIS302DL_REG_FF_WU_CFG_1);
659 + lis->regs[LIS302DL_REG_FF_WU_THS_1] =
660 + reg_read(lis, LIS302DL_REG_FF_WU_THS_1);
661 + lis->regs[LIS302DL_REG_FF_WU_DURATION_1] =
662 + reg_read(lis, LIS302DL_REG_FF_WU_DURATION_1);
663 + lis->regs[LIS302DL_REG_FF_WU_CFG_2] =
664 + reg_read(lis, LIS302DL_REG_FF_WU_CFG_2);
665 + lis->regs[LIS302DL_REG_FF_WU_THS_2] =
666 + reg_read(lis, LIS302DL_REG_FF_WU_THS_2);
667 + lis->regs[LIS302DL_REG_FF_WU_DURATION_2] =
668 + reg_read(lis, LIS302DL_REG_FF_WU_DURATION_2);
669 + lis->regs[LIS302DL_REG_CLICK_CFG] =
670 + reg_read(lis, LIS302DL_REG_CLICK_CFG);
671 + lis->regs[LIS302DL_REG_CLICK_THSY_X] =
672 + reg_read(lis, LIS302DL_REG_CLICK_THSY_X);
673 + lis->regs[LIS302DL_REG_CLICK_THSZ] =
674 + reg_read(lis, LIS302DL_REG_CLICK_THSZ);
675 + lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT] =
676 + reg_read(lis, LIS302DL_REG_CLICK_TIME_LIMIT);
677 + lis->regs[LIS302DL_REG_CLICK_LATENCY] =
678 + reg_read(lis, LIS302DL_REG_CLICK_LATENCY);
679 + lis->regs[LIS302DL_REG_CLICK_WINDOW] =
680 + reg_read(lis, LIS302DL_REG_CLICK_WINDOW);
682 + /* determine if we want to wake up from the accel. */
683 + if (!(lis->flags & LIS302DL_F_WUP_FF ||
684 + lis->flags & LIS302DL_F_WUP_CLICK)) {
687 + tmp = reg_read(lis, LIS302DL_REG_CTRL1);
688 + tmp &= ~LIS302DL_CTRL1_PD;
689 + reg_write(lis, LIS302DL_REG_CTRL1, tmp);
695 +static int lis302dl_resume(struct spi_device *spi)
697 + struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
699 + /* restore registers after resume */
700 + reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
701 + reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
702 + reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
703 + reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
704 + lis->regs[LIS302DL_REG_FF_WU_CFG_1]);
705 + reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
706 + lis->regs[LIS302DL_REG_FF_WU_THS_1]);
707 + reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
708 + lis->regs[LIS302DL_REG_FF_WU_DURATION_1]);
709 + reg_write(lis, LIS302DL_REG_FF_WU_CFG_2,
710 + lis->regs[LIS302DL_REG_FF_WU_CFG_2]);
711 + reg_write(lis, LIS302DL_REG_FF_WU_THS_2,
712 + lis->regs[LIS302DL_REG_FF_WU_THS_2]);
713 + reg_write(lis, LIS302DL_REG_FF_WU_DURATION_2,
714 + lis->regs[LIS302DL_REG_FF_WU_DURATION_2]);
715 + reg_write(lis, LIS302DL_REG_CLICK_CFG,
716 + lis->regs[LIS302DL_REG_CLICK_CFG]);
717 + reg_write(lis, LIS302DL_REG_CLICK_THSY_X,
718 + lis->regs[LIS302DL_REG_CLICK_THSY_X]);
719 + reg_write(lis, LIS302DL_REG_CLICK_THSZ,
720 + lis->regs[LIS302DL_REG_CLICK_THSZ]);
721 + reg_write(lis, LIS302DL_REG_CLICK_TIME_LIMIT,
722 + lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT]);
723 + reg_write(lis, LIS302DL_REG_CLICK_LATENCY,
724 + lis->regs[LIS302DL_REG_CLICK_LATENCY]);
725 + reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
726 + lis->regs[LIS302DL_REG_CLICK_WINDOW]);
731 +#define lis302dl_suspend NULL
732 +#define lis302dl_resume NULL
735 +static struct spi_driver lis302dl_driver = {
737 + .name = "lis302dl",
738 + .owner = THIS_MODULE,
741 + .probe = lis302dl_probe,
742 + .remove = __devexit_p(lis302dl_remove),
743 + .suspend = lis302dl_suspend,
744 + .resume = lis302dl_resume,
747 +static int __init lis302dl_init(void)
749 + return spi_register_driver(&lis302dl_driver);
752 +static void __exit lis302dl_exit(void)
754 + spi_unregister_driver(&lis302dl_driver);
757 +MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
758 +MODULE_LICENSE("GPL");
760 +module_init(lis302dl_init);
761 +module_exit(lis302dl_exit);
762 diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
764 index 0000000..d0f31be
766 +++ b/include/linux/lis302dl.h
768 +#ifndef _LINUX_LIS302DL_H
769 +#define _LINUX_LIS302DL_H
771 +#include <linux/types.h>
773 +struct lis302dl_platform_data {
777 +#endif /* _LINUX_LIS302DL_H */