-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Folks with this patch motion sensors are visibly working via hexdump and
the work queue is discarded for a private IRQ-safe bitbang
implementation in the ISR.

Werner this would be good to have if you don't see a serious problem,
since the current tree is slowed to a crawl by the existing level
sensitive interrupt stuff.

- -Andy
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iD8DBQFHnccpOjLpvpq7dMoRAu1uAJ9HIqgxWp+Q11xGOCIPdygUuBiLNACfbLSs
WKbKhPpNkGZR69GXvwEKhW4=
=AYjf
-----END PGP SIGNATURE-----
motion-sensors-irq-spi.patch

From: Andy Green <[EMAIL PROTECTED]>

This patch removes the workqueue method originally implemented for
motion sensor service and replaces with with a platform-defined
callback which is used in the ISR.

An implementation for the callback is also provided which performs
IRQ-safe SPI bitbang at high speed to service the motion sensor
and insert the x y z data into the input queue.

Interrupts are changed to edge trigger from level removing the
sluggish behaviour.

Interrupts are serviced in typ 75 - 100us without involving the
scheduler now.

The input event interface was broken, this also fixes it.

# cat /proc/bus/input/devices
...
I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="lis302-1 (top)"
P: Phys=
S: Sysfs=/devices/virtual/input/input2
U: Uniq=
H: Handlers=event2
B: EV=5
B: REL=7

I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="lis302-2 (bottom)"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: EV=5
B: REL=7

Data is scaled to be report in mG, so 1000 = 1G.

Data should be reported at 100 sps per axis.
You can sample the X Y Z data easily through hexdump.
Hexdump on a serial terminal can't keep up with the
data, so it is not shown in order.

# hexdump /dev/input/event2
...
00009c0 55d7 478e 70bd 000d 0002 0000 ffdc ffff
00009d0 55d7 478e 712d 000d 0002 0002 03de 0000
00009e0 55d7 478e 714b 000d 0000 0000 0000 0000
00009f0 55d7 478e 976b 000d 0002 0000 ffee ffff
0000a00 55d7 478e 97c9 000d 0002 0001 0012 0000
0000a10 55d7 478e 97f2 000d 0002 0002 03de 0000
0000a20 55d7 478e 980f 000d 0000 0000 0000 0000

The first 8 bytes are timestamp info.
The next 16-bit word is EV_REL to show it is relative
coordinate data.
The next word is 0000=X, 0001=Y, 0002=Z
The last 32 bits on each line is the sample data, in
signed milli-G.

You can single out just one coordinate for rough testing
like this

# hexdump /dev/input/event3 | grep ".* .* .* .* .* 0002 0002 .* .*$" | cut -d' ' -f8
03a8
03ba
03a8
03a8
03ba
03a8
03a8
03a8
03ba
...

Due to tolerances 1G is reported as ~0x3ba milli-G == 954mG
on the sensor I looked at.  Or it could be the alien space
drive I mounted on my roof.

Signed-off-by: Andy Green <[EMAIL PROTECTED]>
---

 arch/arm/mach-s3c2440/mach-gta02.c |   82 ++++++++++++
 drivers/input/misc/lis302dl.c      |  246 +++++++++---------------------------
 include/linux/lis302dl.h           |  100 +++++++++++++++
 3 files changed, 242 insertions(+), 186 deletions(-)


diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 1b682ec..c952a76 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -525,13 +525,93 @@ static struct platform_device gta01_led_dev = {
 
 /* SPI: Accelerometers attached to SPI of s3c244x */
 
-static const struct lis302dl_platform_data lis302_pdata[] = {
+/*
+ * Situation is that Linux SPI can't work in an interrupt context, so we
+ * implement our own bitbang here.  Arbitration is needed because not only
+ * can this interrupt happen at any time even if foreground wants to use
+ * the bitbang API from Linux, but multiple motion sensors can be on the
+ * same SPI bus, and multiple interrupts can happen.
+ *
+ * Foreground / interrupt arbitration is okay because the interrupts are
+ * disabled around all the foreground SPI code.
+ *
+ * Interrupt / Interrupt arbitration is okay because the interrupts are
+ * at the same priority (I think)
+ *
+ * Servicing is typ 75 - 100us at 400MHz.
+ */
+
+/* #define DEBUG_SPEW_MS */
+#define MG_PER_SAMPLE 18
+
+void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
+{
+	struct lis302dl_platform_data *pdata = lis->pdata;
+	u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
+	int n, n1;
+#ifdef DEBUG_SPEW_MS
+	s8 x, y, z;
+#endif
+
+	s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
+	for (n = 0; n < 8; n++) { /* write the r/w, inc and address */
+		s3c2410_gpio_setpin(pdata->pin_clk, 0);
+		s3c2410_gpio_setpin(pdata->pin_mosi, (shifter >> 7) & 1);
+		s3c2410_gpio_setpin(pdata->pin_clk, 1);
+		shifter <<= 1;
+	}
+	for (n = 0; n < 5; n++) { /* 5 consequetive registers */
+		for (n1 = 0; n1 < 8; n1++) { /* 8 bits each */
+			s3c2410_gpio_setpin(pdata->pin_clk, 0);
+			s3c2410_gpio_setpin(pdata->pin_clk, 1);
+			shifter <<= 1;
+			if (s3c2410_gpio_getpin(pdata->pin_miso))
+				shifter |= 1;
+		}
+		switch (n) {
+		case 0:
+#ifdef DEBUG_SPEW_MS
+			x = shifter;
+#endif
+			input_report_rel(lis->input_dev, REL_X, MG_PER_SAMPLE * (s8)shifter);
+			break;
+		case 2:
+#ifdef DEBUG_SPEW_MS
+			y = shifter;
+#endif
+			input_report_rel(lis->input_dev, REL_Y, MG_PER_SAMPLE * (s8)shifter);
+			break;
+		case 4:
+#ifdef DEBUG_SPEW_MS
+			z = shifter;
+#endif
+			input_report_rel(lis->input_dev, REL_Z, MG_PER_SAMPLE * (s8)shifter);
+			break;
+		}
+	}
+	s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
+	input_sync(lis->input_dev);
+#ifdef DEBUG_SPEW_MS
+	printk("%s: %d %d %d\n", pdata->name, x, y, z);
+#endif
+}
+
+
+const struct lis302dl_platform_data lis302_pdata[] = {
 	{
 		.name		= "lis302-1 (top)",
 		.pin_chip_select= S3C2410_GPD12,
+		.pin_clk	= S3C2410_GPG7,
+		.pin_mosi	= S3C2410_GPG6,
+		.pin_miso	= S3C2410_GPG5,
+		.lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
 	}, {
 		.name		= "lis302-2 (bottom)",
 		.pin_chip_select= S3C2410_GPD13,
+		.pin_clk	= S3C2410_GPG7,
+		.pin_mosi	= S3C2410_GPG6,
+		.pin_miso	= S3C2410_GPG5,
+		.lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
 	},
 };
 
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 2cb2921..4ab66c4 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -33,110 +33,17 @@
 #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,
-	LIS302DL_CTRL3_IHL		= 0x80,
-};
-
-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	0x80
-#define	ADDR_MASK	0x3f
+#define READ_BIT		0x80
+#define READ_BIT_INC_ADS	0xc0
+#define	ADDR_MASK		0x3f
 
 static u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
 {
@@ -233,7 +140,7 @@ static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
 		BUG();
 	}
 }
-
+#if 0
 static void _report_btn_single(struct input_dev *inp, int btn)
 {
 	input_report_key(inp, btn, 1);
@@ -251,84 +158,14 @@ static void _report_btn_double(struct input_dev *inp, int btn)
 	input_sync(inp);
 	input_report_key(inp, btn, 0);
 }
+#endif
 
-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, ff_wu_src_2, click_src;
-	u_int8_t val_x, val_y, val_z;
-
-	lis->working = 1;
-
-	status = reg_read(lis, LIS302DL_REG_STATUS);
-	ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
-	ff_wu_src_2 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
-	click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
-
-	if (status & LIS302DL_STATUS_XYZDA) {
-		val_x = reg_read(lis, LIS302DL_REG_OUT_X);
-		if (lis->flags & LIS302DL_F_FS)
-			val_x = val_x << 2;
-		input_report_rel(lis->input_dev, REL_X, val_x);
-		val_y = reg_read(lis, LIS302DL_REG_OUT_Y);
-		if (lis->flags & LIS302DL_F_FS)
-			val_y = val_y << 2;
-		input_report_rel(lis->input_dev, REL_Y, val_y);
-		val_z = reg_read(lis, LIS302DL_REG_OUT_Z);
-		if (lis->flags & LIS302DL_F_FS)
-			val_z = val_z << 2;
-		input_report_rel(lis->input_dev, REL_Z, val_z);
-//		printk("%p: x=%d, y=%d, z=%d\n", lis, val_x, val_y, val_z);
-	}
-	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 irqreturn_t lis302dl_interrupt(int irq, void *_lis)
 {
 	struct lis302dl_info *lis = _lis;
 
-	get_device(&lis->spi_dev->dev);
-
-	if (!schedule_work(&lis->work))
-		if (!lis->working)
-			dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
-
-	/* Disable any further interrupts until we have processed
-	 * the current one */
-	disable_irq(lis->spi_dev->irq);
-
+	(lis->pdata->lis302dl_bitbang_read)(lis);
 	return IRQ_HANDLED;
 }
 
@@ -402,9 +239,16 @@ 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;
+	unsigned long flags;
 
+	local_save_flags(flags);
 	/* make sure we're powered up and generate data ready */
 	reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
+	local_irq_restore(flags);
+
+	/* kick it off -- since we are edge triggered, if we missed the edge
+	 * permanent low interrupt is death for us */
+	(lis->pdata->lis302dl_bitbang_read)(lis);
 
 	return 0;
 }
@@ -414,6 +258,9 @@ 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;
+	unsigned long flags;
+
+	local_save_flags(flags);
 
 	/* since the input core already serializes access and makes sure we
 	 * only see close() for the close of the last user, we can safely
@@ -426,6 +273,7 @@ static void lis302dl_input_close(struct input_dev *inp)
 		reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
 				 0x00);
 	}
+	local_irq_restore(flags);
 }
 
 static int __devinit lis302dl_probe(struct spi_device *spi)
@@ -433,17 +281,22 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 	int rc;
 	struct lis302dl_info *lis;
 	u_int8_t wai;
+	unsigned long flags;
+	struct lis302dl_platform_data *pdata;
 
 	lis = kzalloc(sizeof(*lis), GFP_KERNEL);
 	if (!lis)
 		return -ENOMEM;
 
+	local_save_flags(flags);
+
 	mutex_init(&lis->lock);
-	INIT_WORK(&lis->work, lis302dl_work);
 	lis->spi_dev = spi;
 
 	spi_set_drvdata(spi, lis);
 
+	pdata = spi->dev.platform_data;
+
 	rc = spi_setup(spi);
 	if (rc < 0) {
 		dev_err(&spi->dev, "error during spi_setup\n");
@@ -459,18 +312,10 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 		goto bail_free_lis;
 	}
 
-	rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
-			 IRQF_TRIGGER_LOW, "lis302dl", lis);
-	if (rc < 0) {
-		dev_err(&spi->dev, "error requesting IRQ %d\n",
-			lis->spi_dev->irq);
-		goto bail_free_lis;
-	}
-
 	rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
 	if (rc) {
 		dev_err(&spi->dev, "error creating sysfs group\n");
-		goto bail_irq;
+		goto bail_free_lis;
 	}
 
 	/* initialize input layer details */
@@ -481,14 +326,18 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 	}
 
 	set_bit(EV_REL, lis->input_dev->evbit);
-	set_bit(EV_KEY, lis->input_dev->evbit);
+	set_bit(REL_X, lis->input_dev->relbit);
+	set_bit(REL_Y, lis->input_dev->relbit);
+	set_bit(REL_Z, lis->input_dev->relbit);
+/*	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->name = pdata->name;
+	 /* SPI Bus not defined as a valid bus for input subsystem*/
+	lis->input_dev->id.bustype = BUS_I2C; /* lie about it */
 	lis->input_dev->open = lis302dl_input_open;
 	lis->input_dev->close = lis302dl_input_close;
 
@@ -519,25 +368,42 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 	reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
 	reg_read(lis, LIS302DL_REG_CLICK_SRC);
 
+	dev_info(&spi->dev, "Found %s\n", pdata->name);
+
+	lis->pdata = pdata;
+
+	rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
+			 IRQF_TRIGGER_FALLING, "lis302dl", lis);
+	if (rc < 0) {
+		dev_err(&spi->dev, "error requesting IRQ %d\n",
+			lis->spi_dev->irq);
+		goto bail_inp_reg;
+	}
+	local_irq_restore(flags);
 	return 0;
 
+bail_inp_reg:
+	input_unregister_device(lis->input_dev);
 bail_inp_dev:
 	input_free_device(lis->input_dev);
 bail_sysfs:
 	sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
-bail_irq:
-	free_irq(lis->spi_dev->irq, NULL);
 bail_free_lis:
 	kfree(lis);
+	local_irq_restore(flags);
 	return rc;
 }
 
 static int __devexit lis302dl_remove(struct spi_device *spi)
 {
 	struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
+	unsigned long flags;
 
 	/* power down the device */
+	local_save_flags(flags);
 	reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
+	local_irq_restore(flags);
+
 	sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
 	input_unregister_device(lis->input_dev);
 	if (lis->input_dev)
@@ -552,6 +418,9 @@ static int __devexit lis302dl_remove(struct spi_device *spi)
 static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
 {
 	struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
+	unsigned long flags;
+
+	local_save_flags(flags);
 
 	/* save registers */
 	lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
@@ -592,12 +461,17 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
 		reg_write(lis, LIS302DL_REG_CTRL1, tmp);
 	}
 
+	local_irq_restore(flags);
+
 	return 0;
 }
 
 static int lis302dl_resume(struct spi_device *spi)
 {
 	struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
+	unsigned long flags;
+
+	local_save_flags(flags);
 
 	/* restore registers after resume */
 	reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
@@ -628,6 +502,8 @@ static int lis302dl_resume(struct spi_device *spi)
 	reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
 		  lis->regs[LIS302DL_REG_CLICK_WINDOW]);
 
+	local_irq_restore(flags);
+
 	return 0;
 }
 #else
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
index e45083a..3612683 100644
--- a/include/linux/lis302dl.h
+++ b/include/linux/lis302dl.h
@@ -2,11 +2,111 @@
 #define _LINUX_LIS302DL_H
 
 #include <linux/types.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+
+
+struct lis302dl_info;
 
 struct lis302dl_platform_data {
 	char *name;
 	unsigned long pin_chip_select;
+	unsigned long pin_clk;
+	unsigned long pin_mosi;
+	unsigned long pin_miso;
+	void (*lis302dl_bitbang_read)(struct lis302dl_info *);
+};
+
+struct lis302dl_info {
+	struct lis302dl_platform_data *pdata;
+	struct spi_device *spi_dev;
+	struct input_dev *input_dev;
+	struct mutex lock;
+	unsigned int flags;
+	u_int8_t regs[0x40];
+};
+
+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,
+	LIS302DL_CTRL3_IHL		= 0x80,
 };
 
+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,
+};
+
+#define LIS302DL_WHO_AM_I_MAGIC		0x3b
+
+#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 */
+
+
 #endif /* _LINUX_LIS302DL_H */
 

Reply via email to