aboutsummaryrefslogtreecommitdiffstats
path: root/target/image/ar7/src/loader.c
blob: 22b909d7e9936c94e8405f0a334a9e56bf92cb3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* inflate.c -- Not copyrighted 1992 by Mark Adler
   version c10p1, 10 January 1993 */

/*
 * Adapted for booting Linux by Hannu Savolainen 1993
 * based on gzip-1.0.3
 *
 * Nicolas Pitre <nico@visuaide.com>, 1999/04/14 :
 *   Little mods for all variable to reside either into rodata or bss segments
 *   by marking constant variables with 'const' and initializing all the others
 *   at run-time only.  This allows for the kernel uncompressor to run
 *   directly from Flash or ROM memory on embeded systems.
 */

#include <linux/config.h>
#include "gzip.h"
#include "LzmaDecode.h"

/* Function prototypes */
unsigned char get_byte(void);
int tikernelunzip(int,char *[], char *[]);
static int tidecompress(uch *, uch *);

void kernel_entry(int, char *[], char *[]);
void (*ke)(int, char *[], char *[]); /* Gen reference to kernel function */
void (*prnt)(unsigned int, char *);		/* Gen reference to Yamon print function */
void printf(char *ptr);			/* Generate our own printf */

int tikernelunzip(int argc, char *argv[], char *arge[])
{
	extern unsigned int _ftext;
	extern uch kernelimage[];
	uch *in, *out;
	int status;

	printf("Launching kernel decompressor.\n");

	out = (unsigned char *) LOADADDR;
	in = &(kernelimage[0]);

	status = tidecompress(in, out);

	if (status == 0) {
		printf("Kernel decompressor was successful ... launching kernel.\n");

		ke = ( void(*)(int, char *[],char*[]))kernel_entry;
		(*ke)(argc,argv,arge);

		return (0);
	} else {
		printf("Error in decompression.\n");
		return(1);
	}
}

#if 0
char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
void print_i(int i)
{
	int j;
	char buf[11];

	buf[0] = '0';
	buf[1] = 'x';
	buf[10] = 0;
	
	for (j = 0; j < 8; j++)
	{
		buf[2 + 7 - j] = hex[i & 0xf];
		i = i >> 4;
	}

	printf(buf);
}
#endif

int tidecompress(uch *indata, uch *outdata)
{
	extern unsigned int workspace;
	extern unsigned char kernelimage[], kernelimage_end[];
	unsigned int i;  /* temp value */
	unsigned int lc; /* literal context bits */
	unsigned int lp; /* literal pos state bits */
	unsigned int pb; /* pos state bits */
	unsigned int osize; /* uncompressed size */
	unsigned int wsize; /* window size */
	unsigned int insize = kernelimage_end - kernelimage;
	int status;
	
	output_ptr = 0;
	output_data = outdata;
	input_data = indata;

	/* lzma args */
	i = get_byte();
	lc = i % 9, i = i / 9;
	lp = i % 5, pb = i / 5;

	/* skip rest of the LZMA coder property */
	for (i = 0; i < 4; i++)
		get_byte();
	
	/* read the lower half of uncompressed size in the header */
	osize = ((unsigned int)get_byte()) +
		((unsigned int)get_byte() << 8) +
		((unsigned int)get_byte() << 16) +
		((unsigned int)get_byte() << 24);

	/* skip rest of the header (upper half of uncompressed size) */
	for (i = 0; i < 4; i++)
		get_byte();
	
	i = 0;
	wsize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb);

	if ((status = LzmaDecode((unsigned char *) &workspace, wsize, lc, lp, pb,
		indata + 13, insize - 13, (unsigned char *) output_data, osize, &i)) == LZMA_RESULT_OK)
			return 0;

	return status;
}


void printf(char *ptr)
{
	unsigned int *tempptr = (unsigned int  *)0x90000534;
	prnt = ( void (*)(unsigned int, char *)) *tempptr;
	(*prnt)(0,ptr);
}

unsigned char get_byte()
{
	unsigned char c;
	
	c = *input_data;
	input_data++;

	return c;
}
n775'>775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
From 0f43da072e28d0bad639cb6823a7759112ff3489 Mon Sep 17 00:00:00 2001
From: mokopatches <mokopatches@openmoko.org>
Date: Wed, 16 Jul 2008 14:46:56 +0100
Subject: [PATCH] gta02-acc.patch

---
 arch/arm/mach-s3c2410/mach-gta01.c      |    2 +-
 arch/arm/mach-s3c2410/mach-qt2410.c     |    2 +-
 arch/arm/mach-s3c2440/mach-gta02.c      |  181 +++++++++++++++--
 drivers/input/misc/lis302dl.c           |  350 ++++++++++++-------------------
 drivers/spi/spi_s3c24xx_gpio.c          |   23 ++-
 include/asm-arm/arch-s3c2410/spi-gpio.h |    6 +-
 include/linux/lis302dl.h                |  102 +++++++++
 7 files changed, 429 insertions(+), 237 deletions(-)

diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c
index 87bb189..0543daa 100644
--- a/arch/arm/mach-s3c2410/mach-gta01.c
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
@@ -510,7 +510,7 @@ static struct spi_board_info gta01_spi_board_info[] = {
 	},
 };
 
-static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
+static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int csidx, int cs)
 {
 	switch (cs) {
 	case BITBANG_CS_ACTIVE:
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index a1caf4b..6f7b56d 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -214,7 +214,7 @@ static struct platform_device qt2410_led = {
 
 /* SPI */
 
-static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
+static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int csidx, int cs)
 {
 	switch (cs) {
 	case BITBANG_CS_ACTIVE:
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index d11da10..3fbb131 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -78,6 +78,9 @@
 
 #include <linux/glamofb.h>
 
+/* arbitrates which sensor IRQ owns the shared SPI bus */
+static spinlock_t motion_irq_lock;
+
 static struct map_desc gta02_iodesc[] __initdata = {
 	{
 		.virtual	= 0xe0000000,
@@ -377,8 +380,6 @@ static struct platform_device *gta02_devices[] __initdata = {
 	&s3c_device_usbgadget,
 	&s3c_device_nand,
 	&s3c_device_ts,
-	&s3c_device_spi0,
-	&s3c_device_spi1,
 	&gta02_nor_flash,
 };
 
@@ -478,10 +479,12 @@ static struct spi_board_info gta02_spi_board_info[] = {
 	},
 };
 
+#if 0 /* currently this is not used and we use gpio spi */
 static struct glamo_spi_info glamo_spi_cfg = {
 	.board_size	= ARRAY_SIZE(gta02_spi_board_info),
 	.board_info	= gta02_spi_board_info,
 };
+#endif /* 0 */
 
 static struct glamo_spigpio_info glamo_spigpio_cfg = {
 	.pin_clk	= GLAMO_GPIO10_OUTPUT,
@@ -507,16 +510,99 @@ static struct platform_device gta01_led_dev = {
 
 /* SPI: Accelerometers attached to SPI of s3c244x */
 
-static void gta02_spi_acc_set_cs(struct s3c2410_spi_info *spi, int cs, int pol)
+/*
+ * 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 evidently needed, otherwise we
+ * lose edge-triggered service after a while due to the two sensors sharing
+ * the SPI bus having irqs at the same time eventually.
+ *
+ * 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)
 {
-	s3c2410_gpio_setpin(cs, pol);
+	struct lis302dl_platform_data *pdata = lis->pdata;
+	u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
+	int n, n1;
+	unsigned long flags;
+#ifdef DEBUG_SPEW_MS
+	s8 x, y, z;
+#endif
+
+	spin_lock_irqsave(&motion_irq_lock, flags);
+	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);
+	spin_unlock_irqrestore(&motion_irq_lock, flags);
+	input_sync(lis->input_dev);
+#ifdef DEBUG_SPEW_MS
+	printk("%s: %d %d %d\n", pdata->name, x, y, z);
+#endif
 }
 
-static const struct lis302dl_platform_data lis302_pdata[] = {
+
+struct lis302dl_platform_data lis302_pdata[] = {
 	{
-		.name		= "lis302-1 (top)"
+		.name		= "lis302-1 (top)",
+		.pin_chip_select= S3C2410_GPD12,
+		.pin_clk	= S3C2410_GPG7,
+		.pin_mosi	= S3C2410_GPG6,
+		.pin_miso	= S3C2410_GPG5,
+		.open_drain	= 1, /* altered at runtime by PCB rev */
+		.lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
 	}, {
-		.name		= "lis302-2 (bottom)"
+		.name		= "lis302-2 (bottom)",
+		.pin_chip_select= S3C2410_GPD13,
+		.pin_clk	= S3C2410_GPG7,
+		.pin_mosi	= S3C2410_GPG6,
+		.pin_miso	= S3C2410_GPG5,
+		.open_drain	= 1, /* altered at runtime by PCB rev */
+		.lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
 	},
 };
 
@@ -525,26 +611,75 @@ 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,
+		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 1,
-		.chip_select	= S3C2410_GPD12,
+		.chip_select	= 0,
 		.mode		= SPI_MODE_3,
 	},
 	{
 		.modalias	= "lis302dl",
 		.platform_data	= &lis302_pdata[1],
 		.irq		= GTA02_IRQ_GSENSOR_2,
-		.max_speed_hz	= 400 * 1000,
+		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 1,
-		.chip_select	= S3C2410_GPD13,
+		.chip_select	= 1,
 		.mode		= SPI_MODE_3,
 	},
 };
 
-static struct s3c2410_spi_info gta02_spi_acc_cfg = {
-	.set_cs		= gta02_spi_acc_set_cs,
+static void spi_acc_cs(struct s3c2410_spigpio_info *spigpio_info,
+		       int csid, int cs)
+{
+	struct lis302dl_platform_data * plat_data =
+				(struct lis302dl_platform_data *)spigpio_info->
+						     board_info->platform_data;
+	switch (cs) {
+	case BITBANG_CS_ACTIVE:
+		s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 0);
+		break;
+	case BITBANG_CS_INACTIVE:
+		s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 1);
+		break;
+	}
+}
+
+static struct s3c2410_spigpio_info spi_gpio_cfg = {
+	.pin_clk	= S3C2410_GPG7,
+	.pin_mosi	= S3C2410_GPG6,
+	.pin_miso	= S3C2410_GPG5,
 	.board_size	= ARRAY_SIZE(gta02_spi_acc_bdinfo),
 	.board_info	= gta02_spi_acc_bdinfo,
+	.chip_select	= &spi_acc_cs,
+	.num_chipselect = 2,
+};
+
+static struct resource s3c_spi_acc_resource[] = {
+	[0] = {
+		.start = S3C2410_GPG3,
+		.end   = S3C2410_GPG3,
+	},
+	[1] = {
+		.start = S3C2410_GPG5,
+		.end   = S3C2410_GPG5,
+	},
+	[2] = {
+		.start = S3C2410_GPG6,
+		.end   = S3C2410_GPG6,
+	},
+	[3] = {
+		.start = S3C2410_GPG7,
+		.end   = S3C2410_GPG7,
+	},
+};
+
+static struct platform_device s3c_device_spi_acc = {
+	.name		  = "spi_s3c24xx_gpio",
+	.id		  = 1,
+	.num_resources	  = ARRAY_SIZE(s3c_spi_acc_resource),
+	.resource	  = s3c_spi_acc_resource,
+	.dev = {
+		.platform_data = &spi_gpio_cfg,
+	},
 };
 
 static struct resource gta02_led_resources[] = {
@@ -786,10 +921,21 @@ static void __init gta02_machine_init(void)
 {
 	int rc;
 
+	switch (system_rev) {
+	case GTA02v6_SYSTEM_REV:
+		/* we need push-pull interrupt from motion sensors */
+		lis302_pdata[0].open_drain = 0;
+		lis302_pdata[1].open_drain = 0;
+		break;
+	default:
+		break;
+	}
+
+	spin_lock_init(&motion_irq_lock);
+
 	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 */
@@ -801,6 +947,12 @@ static void __init gta02_machine_init(void)
 		break;
 	}
 
+	/* acc sensor chip selects */
+	s3c2410_gpio_setpin(S3C2410_GPD12, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPD12, S3C2410_GPIO_OUTPUT);
+	s3c2410_gpio_setpin(S3C2410_GPD13, 1);
+	s3c2410_gpio_cfgpin(S3C2410_GPD13, S3C2410_GPIO_OUTPUT);
+
 	INIT_WORK(&gta02_udc_vbus_drawer.work, __gta02_udc_vbus_draw);
 	s3c24xx_udc_set_platdata(&gta02_udc_cfg);
 	set_s3c2410ts_info(&gta02_ts_cfg);
@@ -829,6 +981,7 @@ static void __init gta02_machine_init(void)
 		break;
 	}
 
+	platform_device_register(&s3c_device_spi_acc);
 	platform_device_register(&gta01_button_dev);
 	platform_device_register(&gta01_pm_gsm_dev);
 
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 45c41c8..36bdcf7 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -33,117 +33,26 @@
 #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
+#define READ_BIT		0x80
+#define READ_BIT_INC_ADS	0xc0
+#define	ADDR_MASK		0x3f
 
-static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
+static 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;
+	BUG_ON(reg & ~ADDR_MASK);
+
+	cmd = reg | READ_BIT;
 
 	rc = spi_w8r8(lis->spi_dev, cmd);
 
@@ -161,11 +70,13 @@ static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
 	return ret;
 }
 
-static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
+static 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);
+	BUG_ON(reg & ~ADDR_MASK);
+
+	buf[0] = reg;
 	buf[1] = val;
 
 	return spi_write(lis->spi_dev, buf, sizeof(buf));
@@ -207,10 +118,10 @@ static int reg_set_bit_mask(struct lis302dl_info *lis,
 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,
+	LIS302DL_INTMODE_FF_WU_2	= 0x02,
+	LIS302DL_INTMODE_FF_WU_12	= 0x03,
+	LIS302DL_INTMODE_DATA_READY	= 0x04,
+	LIS302DL_INTMODE_CLICK		= 0x07,
 };
 
 static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
@@ -218,12 +129,18 @@ static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
 {
 	struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
 
-	if (int_pin == 1)
+	switch (int_pin) {
+	case 1:
 		reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
-	else if (int_pin == 2)
+		break;
+	case 2:
 		reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
+		break;
+	default:
+		BUG();
+	}
 }
-
+#if 0
 static void _report_btn_single(struct input_dev *inp, int btn)
 {
 	input_report_key(inp, btn, 1);
@@ -241,95 +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, 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);
-
+	(lis->pdata->lis302dl_bitbang_read)(lis);
 	return IRQ_HANDLED;
 }
 
@@ -388,6 +224,7 @@ 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,
+	NULL
 };
 
 static struct attribute_group lis302dl_attr_group = {
@@ -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,9 +258,12 @@ 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 lastre user, we can safely
+	 * only see close() for the close of the last user, we can safely
 	 * disable the data ready events */
 	reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
 
@@ -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,84 +281,138 @@ 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) {
-		printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
+		dev_err(&spi->dev, "error during spi_setup\n");
 		dev_set_drvdata(&spi->dev, NULL);
-		kfree(lis);
-		return rc;
+		goto bail_free_lis;
 	}
 
 	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_err(&spi->dev, "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 = -ENODEV;
+		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");
-		/* FIXME */
-		return rc;
+		goto bail_free_lis;
 	}
 
 	/* 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 */
+		goto bail_sysfs;
 	}
 
 	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;
 
-	input_register_device(lis->input_dev);
+	rc = input_register_device(lis->input_dev);
+	if (rc) {
+		dev_err(&spi->dev, "error %d registering input device\n", rc);
+		goto bail_inp_dev;
+	}
+
+	reg_write(lis, LIS302DL_REG_CTRL1, 0x47);
+	reg_write(lis, LIS302DL_REG_CTRL3, 0xc0);
+	reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x14);
+	reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
+	reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x95);
+
+	reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
+					   LIS302DL_CTRL1_Yen |
+			 		   LIS302DL_CTRL1_Zen);
+
+	if (pdata->open_drain)
+		/* switch interrupt to open collector, active-low */
+		reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
+						   LIS302DL_CTRL3_IHL);
+	else
+		/* push-pull, active-low */
+		reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
+
+	lis302dl_int_mode(spi, 1, LIS302DL_INTMODE_DATA_READY);
+	lis302dl_int_mode(spi, 2, LIS302DL_INTMODE_DATA_READY);
+
+	reg_read(lis, LIS302DL_REG_STATUS);
+	reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+	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_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)
+		input_free_device(lis->input_dev);
 	dev_set_drvdata(&spi->dev, NULL);
 	kfree(lis);
 
@@ -521,6 +423,10 @@ 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;
+
+	disable_irq(lis->spi_dev->irq);
+	local_save_flags(flags);
 
 	/* save registers */
 	lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
@@ -561,12 +467,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]);
@@ -597,6 +508,9 @@ 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);
+	enable_irq(lis->spi_dev->irq);
+
 	return 0;
 }
 #else
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index e33f614..ccadf35 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -91,7 +91,7 @@ static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
 	struct s3c2410_spigpio *sg = spidev_to_sg(dev);
 
 	if (sg->info && sg->info->chip_select)
-		(sg->info->chip_select)(sg->info, value);
+		(sg->info->chip_select)(sg->info, dev->chip_select, value);
 }
 
 static int s3c2410_spigpio_probe(struct platform_device *dev)
@@ -100,6 +100,7 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
 	struct spi_master	*master;
 	struct s3c2410_spigpio  *sp;
 	int ret;
+	int i;
 
 	master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
 	if (master == NULL) {
@@ -112,9 +113,11 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
 
 	platform_set_drvdata(dev, sp);
 
-	/* copy in the plkatform data */
+	/* copy in the platform data */
 	info = sp->info = dev->dev.platform_data;
 
+	master->num_chipselect = info->num_chipselect;
+
 	/* setup spi bitbang adaptor */
 	sp->bitbang.master = spi_master_get(master);
 	sp->bitbang.master->bus_num = info->bus_num;
@@ -142,6 +145,22 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
 	if (ret)
 		goto err_no_bitbang;
 
+	/* register the chips to go with the board */
+
+	for (i = 0; i < sp->info->board_size; i++) {
+		struct spi_device *spidev;
+
+		dev_info(&dev->dev, "registering %p: %s\n",
+			 &sp->info->board_info[i],
+			 sp->info->board_info[i].modalias);
+
+		sp->info->board_info[i].controller_data = sp;
+		spidev = spi_new_device(master, sp->info->board_info + i);
+		if (spidev)
+			spidev->max_speed_hz =
+					  sp->info->board_info[i].max_speed_hz;
+	}
+
 	return 0;
 
  err_no_bitbang:
diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h
index 7380373..d4efc97 100644
--- a/include/asm-arm/arch-s3c2410/spi-gpio.h
+++ b/include/asm-arm/arch-s3c2410/spi-gpio.h
@@ -19,8 +19,12 @@ struct s3c2410_spigpio_info {
 	unsigned long		 pin_miso;
 
 	int			 bus_num;
+	int			 num_chipselect;
 
-	void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
+	unsigned long		 board_size;
+	struct spi_board_info	*board_info;
+
+	void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs);
 };
 
 
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
index d0f31be..2dea813 100644
--- a/include/linux/lis302dl.h
+++ b/include/linux/lis302dl.h
@@ -2,10 +2,112 @@
 #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;
+	int open_drain;
+	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 */
 
-- 
1.5.6.3