aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch')
-rw-r--r--recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch1759
1 files changed, 0 insertions, 1759 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch b/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch
deleted file mode 100644
index 4365e9312a..0000000000
--- a/recipes/linux/linux-openmoko-2.6.34/0001-accels.patch.patch
+++ /dev/null
@@ -1,1759 +0,0 @@
-From 1b8efb3ae35ba6a3dfcf03b28bab9ce945a9b294 Mon Sep 17 00:00:00 2001
-From: Radek Polak <psonek2@seznam.cz>
-Date: Fri, 9 Apr 2010 09:15:40 +0200
-Subject: [PATCH 11/17] accels.patch
-
-adds support for accelerometers. You will need include/linux/lis302dl.h and
-drivers/input/misc/lis302dl.c from andy-tracking. The patch needs
-spi_bitbang_transfer_sync() and bitbang_work() to be ported correctly (some
-fixes from original 2.6.32 are missing).
-
-Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
----
- arch/arm/mach-s3c2410/include/mach/spi-gpio.h | 3 +-
- arch/arm/mach-s3c2440/mach-gta02.c | 157 ++++
- drivers/input/misc/Kconfig | 9 +
- drivers/input/misc/Makefile | 1 +
- drivers/input/misc/lis302dl.c | 952 +++++++++++++++++++++++++
- drivers/spi/spi_bitbang.c | 231 ++++---
- drivers/spi/spi_s3c24xx_gpio.c | 7 +-
- include/linux/lis302dl.h | 152 ++++
- include/linux/spi/spi.h | 30 +
- include/linux/spi/spi_bitbang.h | 5 +
- 10 files changed, 1433 insertions(+), 114 deletions(-)
- create mode 100644 drivers/input/misc/lis302dl.c
- create mode 100644 include/linux/lis302dl.h
-
-diff --git a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
-index dcef228..8eedc9c 100644
---- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
-+++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
-@@ -21,7 +21,8 @@ struct s3c2410_spigpio_info {
- int num_chipselect;
- int bus_num;
-
-- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
-+ int non_blocking_transfer;
-+ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs);
- };
-
-
-diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
-index 9a9461d..1fa93b4 100644
---- a/arch/arm/mach-s3c2440/mach-gta02.c
-+++ b/arch/arm/mach-s3c2440/mach-gta02.c
-@@ -62,6 +62,7 @@
-
- #include <linux/input.h>
- #include <linux/gpio_keys.h>
-+#include <linux/lis302dl.h>
-
- #include <linux/leds.h>
- #include <linux/leds_pwm.h>
-@@ -111,6 +112,22 @@
- #include <linux/glamofb.h>
- #include <linux/mfd/glamo.h>
-
-+#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
-+
-+#define S3C2410_GPIO_BANKD (32*3)
-+#define S3C2410_GPIO_BANKG (32*6)
-+
-+#define S3C2410_GPG5 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5)
-+#define S3C2410_GPG6 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6)
-+#define S3C2410_GPG7 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 7)
-+#define S3C2410_GPD12 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 12)
-+#define S3C2410_GPD13 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 13)
-+
-+#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
-+#define BITBANG_CS_INACTIVE 0
-+
-+#define S3C_SYSTEM_REV_ATAG GTA02v6_SYSTEM_REV
-+
- static struct pcf50633 *gta02_pcf;
-
- /*
-@@ -322,6 +339,60 @@ const static struct jbt6k74_platform_data jbt6k74_pdata = {
- .gpio_reset = GTA02_GPIO_GLAMO(4),
- };
-
-+/*----------- SPI: Accelerometers attached to SPI of s3c244x ----------------- */
-+
-+void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
-+{
-+ struct lis302dl_platform_data *pdata = lis->pdata;
-+
-+ if (!resume) {
-+ /*
-+ * we don't want to power them with a high level
-+ * because GSENSOR_3V3 is not up during suspend
-+ */
-+ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
-+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
-+ s3c2410_gpio_setpin(pdata->pin_mosi, 0);
-+ /* misnomer: it is a pullDOWN in 2442 */
-+ s3c2410_gpio_pullup(pdata->pin_miso, 1);
-+ return;
-+ }
-+
-+ /* back to normal */
-+ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
-+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
-+ /* misnomer: it is a pullDOWN in 2442 */
-+ s3c2410_gpio_pullup(pdata->pin_miso, 0);
-+
-+ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT);
-+ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT);
-+ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT);
-+ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT);
-+
-+}
-+
-+struct lis302dl_platform_data lis302_pdata_top = {
-+ .name = "lis302-1 (top)",
-+ .pin_chip_select= S3C2410_GPD12,
-+ .pin_clk = S3C2410_GPG7,
-+ .pin_mosi = S3C2410_GPG6,
-+ .pin_miso = S3C2410_GPG5,
-+ .interrupt = GTA02_IRQ_GSENSOR_1,
-+ .open_drain = 1, /* altered at runtime by PCB rev */
-+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
-+};
-+
-+struct lis302dl_platform_data lis302_pdata_bottom = {
-+ .name = "lis302-2 (bottom)",
-+ .pin_chip_select= S3C2410_GPD13,
-+ .pin_clk = S3C2410_GPG7,
-+ .pin_mosi = S3C2410_GPG6,
-+ .pin_miso = S3C2410_GPG5,
-+ .interrupt = GTA02_IRQ_GSENSOR_2,
-+ .open_drain = 1, /* altered at runtime by PCB rev */
-+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
-+};
-+
- static struct spi_board_info gta02_spi_board_info[] = {
- {
- .modalias = "jbt6k74",
-@@ -332,6 +403,81 @@ static struct spi_board_info gta02_spi_board_info[] = {
- .bus_num = 2,
- .chip_select = 0
- },
-+ {
-+ .modalias = "lis302dl",
-+ /* platform_data */
-+ .platform_data = &lis302_pdata_top,
-+ /* controller_data */
-+ /* irq */
-+ .max_speed_hz = 100 * 1000,
-+ .bus_num = 3,
-+ .chip_select = 0,
-+ },
-+ {
-+ .modalias = "lis302dl",
-+ /* platform_data */
-+ .platform_data = &lis302_pdata_bottom,
-+ /* controller_data */
-+ /* irq */
-+ .max_speed_hz = 100 * 1000,
-+ .bus_num = 3,
-+ .chip_select = 1,
-+ },
-+};
-+
-+static void gta02_lis302_chip_select(struct s3c2410_spigpio_info *info, int csid, int cs)
-+{
-+
-+ /*
-+ * Huh... "quirk"... CS on this device is not really "CS" like you can
-+ * expect.
-+ *
-+ * When it is 0 it selects SPI interface mode.
-+ * When it is 1 it selects I2C interface mode.
-+ *
-+ * Because we have 2 devices on one interface we have to make sure
-+ * that the "disabled" device (actually in I2C mode) don't think we're
-+ * talking to it.
-+ *
-+ * When we talk to the "enabled" device, the "disabled" device sees
-+ * the clocks as I2C clocks, creating havoc.
-+ *
-+ * I2C sees MOSI going LOW while CLK HIGH as a START action, thus we
-+ * must ensure this is never issued.
-+ */
-+
-+ int cs_gpio, other_cs_gpio;
-+
-+ cs_gpio = csid ? S3C2410_GPD13 : S3C2410_GPD12;
-+ other_cs_gpio = (1 - csid) ? S3C2410_GPD13 : S3C2410_GPD12;
-+
-+
-+ if (cs == BITBANG_CS_ACTIVE) {
-+ s3c2410_gpio_setpin(other_cs_gpio, 1);
-+ s3c2410_gpio_setpin(cs_gpio, 1);
-+ s3c2410_gpio_setpin(info->pin_clk, 1);
-+ s3c2410_gpio_setpin(cs_gpio, 0);
-+ } else {
-+ s3c2410_gpio_setpin(cs_gpio, 1);
-+ s3c2410_gpio_setpin(other_cs_gpio, 1);
-+ }
-+}
-+
-+static struct s3c2410_spigpio_info gta02_spigpio_cfg = {
-+ .pin_clk = S3C2410_GPG7,
-+ .pin_mosi = S3C2410_GPG6,
-+ .pin_miso = S3C2410_GPG5,
-+ .bus_num = 3,
-+ .num_chipselect = 2,
-+ .chip_select = gta02_lis302_chip_select,
-+ .non_blocking_transfer = 1,
-+};
-+
-+static struct platform_device gta02_spi_gpio_dev = {
-+ .name = "spi_s3c24xx_gpio",
-+ .dev = {
-+ .platform_data = &gta02_spigpio_cfg,
-+ },
- };
-
- static struct resource gta02_glamo_resources[] = {
-@@ -1091,6 +1237,7 @@ static struct platform_device *gta02_devices[] __initdata = {
- &gta02_pm_bt_dev,
- &gta02_pm_wlan_dev,
- &gta02_glamo_dev,
-+ &gta02_spi_gpio_dev,
- &s3c_device_adc,
- &s3c_device_ts,
- };
-@@ -1302,6 +1449,16 @@ static void __init gta02_machine_init(void)
- /* Set the panic callback to make AUX LED blink at ~5Hz. */
- panic_blink = gta02_panic_blink;
-
-+ switch (S3C_SYSTEM_REV_ATAG) {
-+ case GTA02v6_SYSTEM_REV:
-+ /* we need push-pull interrupt from motion sensors */
-+ lis302_pdata_top.open_drain = 0;
-+ lis302_pdata_bottom.open_drain = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+
- bus_register_notifier(&platform_bus_type, &gta02_device_register_notifier);
- bus_register_notifier(&spi_bus_type, &gta02_device_register_notifier);
-
-diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
-index 23140a3..d8d0932 100644
---- a/drivers/input/misc/Kconfig
-+++ b/drivers/input/misc/Kconfig
-@@ -340,4 +340,13 @@ config INPUT_PCAP
- To compile this driver as a module, choose M here: the
- module will be called pcap_keys.
-
-+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 7e95a5d..5b810db 100644
---- a/drivers/input/misc/Makefile
-+++ b/drivers/input/misc/Makefile
-@@ -32,4 +32,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o
- obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
- obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
- obj-$(CONFIG_INPUT_YEALINK) += yealink.o
-+obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
-
-diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
-new file mode 100644
-index 0000000..d345bfb
---- /dev/null
-+++ b/drivers/input/misc/lis302dl.c
-@@ -0,0 +1,952 @@
-+/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
-+ *
-+ * Copyright (C) 2007-2008 by Openmoko, Inc.
-+ * Author: Harald Welte <laforge@openmoko.org>
-+ * converted to private bitbang by:
-+ * Andy Green <andy@openmoko.com>
-+ * ability to set acceleration threshold added by:
-+ * Simon Kagstrom <simon.kagstrom@gmail.com>
-+ * 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/irq.h>
-+#include <linux/interrupt.h>
-+#include <linux/sysfs.h>
-+#include <linux/spi/spi.h>
-+
-+#include <linux/lis302dl.h>
-+
-+/* Utility functions */
-+static u8 __reg_read(struct lis302dl_info *lis, u8 reg)
-+{
-+ struct spi_message msg;
-+ struct spi_transfer t;
-+ u8 data[2] = {0xc0 | reg};
-+ int rc;
-+
-+ spi_message_init(&msg);
-+ memset(&t, 0, sizeof t);
-+ t.len = 2;
-+ spi_message_add_tail(&t, &msg);
-+ t.tx_buf = &data[0];
-+ t.rx_buf = &data[0];
-+
-+ /* Should complete without blocking */
-+ rc = spi_non_blocking_transfer(lis->spi, &msg);
-+ if (rc < 0) {
-+ dev_err(lis->dev, "Error reading register\n");
-+ return rc;
-+ }
-+
-+ return data[1];
-+}
-+
-+static void __reg_write(struct lis302dl_info *lis, u8 reg, u8 val)
-+{
-+ struct spi_message msg;
-+ struct spi_transfer t;
-+ u8 data[2] = {reg, val};
-+
-+ spi_message_init(&msg);
-+ memset(&t, 0, sizeof t);
-+ t.len = 2;
-+ spi_message_add_tail(&t, &msg);
-+ t.tx_buf = &data[0];
-+ t.rx_buf = &data[0];
-+
-+ /* Completes without blocking */
-+ if (spi_non_blocking_transfer(lis->spi, &msg) < 0)
-+ dev_err(lis->dev, "Error writing register\n");
-+}
-+
-+static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
-+ u8 val)
-+{
-+ u_int8_t tmp;
-+
-+ val &= mask;
-+
-+ tmp = __reg_read(lis, reg);
-+ tmp &= ~mask;
-+ tmp |= val;
-+ __reg_write(lis, reg, tmp);
-+}
-+
-+static int __ms_to_duration(struct lis302dl_info *lis, int ms)
-+{
-+ /* If we have 400 ms sampling rate, the stepping is 2.5 ms,
-+ * on 100 ms the stepping is 10ms */
-+ if (lis->flags & LIS302DL_F_DR)
-+ return min((ms * 10) / 25, 637);
-+
-+ return min(ms / 10, 2550);
-+}
-+
-+static int __duration_to_ms(struct lis302dl_info *lis, int duration)
-+{
-+ if (lis->flags & LIS302DL_F_DR)
-+ return (duration * 25) / 10;
-+
-+ return duration * 10;
-+}
-+
-+static u8 __mg_to_threshold(struct lis302dl_info *lis, int mg)
-+{
-+ /* If FS is set each bit is 71mg, otherwise 18mg. The THS register
-+ * has 7 bits for the threshold value */
-+ if (lis->flags & LIS302DL_F_FS)
-+ return min(mg / 71, 127);
-+
-+ return min(mg / 18, 127);
-+}
-+
-+static int __threshold_to_mg(struct lis302dl_info *lis, u8 threshold)
-+{
-+ if (lis->flags & LIS302DL_F_FS)
-+ return threshold * 71;
-+
-+ return threshold * 18;
-+}
-+
-+/* interrupt handling related */
-+
-+enum lis302dl_intmode {
-+ LIS302DL_INTMODE_GND = 0x00,
-+ LIS302DL_INTMODE_FF_WU_1 = 0x01,
-+ 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 device *dev, int int_pin,
-+ enum lis302dl_intmode mode)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ switch (int_pin) {
-+ case 1:
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
-+ break;
-+ case 2:
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
-+ break;
-+ default:
-+ BUG();
-+ }
-+}
-+
-+static void __enable_wakeup(struct lis302dl_info *lis)
-+{
-+ __reg_write(lis, LIS302DL_REG_CTRL1, 0);
-+
-+ /* First zero to get to a known state */
-+ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
-+ LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE |
-+ LIS302DL_FFWUCFG_LIR);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
-+ __mg_to_threshold(lis, lis->wakeup.threshold));
-+ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
-+ __ms_to_duration(lis, lis->wakeup.duration));
-+
-+ /* Route the interrupt for wakeup */
-+ __lis302dl_int_mode(lis->dev, 1,
-+ LIS302DL_INTMODE_FF_WU_1);
-+
-+ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
-+ __reg_read(lis, LIS302DL_REG_OUT_X);
-+ __reg_read(lis, LIS302DL_REG_OUT_Y);
-+ __reg_read(lis, LIS302DL_REG_OUT_Z);
-+ __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_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
-+}
-+
-+static void __enable_data_collection(struct lis302dl_info *lis)
-+{
-+ 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);
-+
-+ /* If the threshold is zero, let the device generated an interrupt
-+ * on each datum */
-+ if (lis->threshold == 0) {
-+ __reg_write(lis, LIS302DL_REG_CTRL2, 0);
-+ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
-+ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
-+ } else {
-+ __reg_write(lis, LIS302DL_REG_CTRL2,
-+ LIS302DL_CTRL2_HPFF1);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
-+ __mg_to_threshold(lis, lis->threshold));
-+ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
-+ __ms_to_duration(lis, lis->duration));
-+
-+ /* Clear the HP filter "starting point" */
-+ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
-+ LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE |
-+ LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR);
-+ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12);
-+ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12);
-+ }
-+}
-+
-+#if 0
-+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);
-+}
-+#endif
-+
-+
-+static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
-+{
-+ u8 data[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 2] = {0xC0 | LIS302DL_REG_STATUS};
-+ u8 *read = data + 1;
-+ unsigned long flags;
-+ int mg_per_sample = __threshold_to_mg(lis, 1);
-+ struct spi_message msg;
-+ struct spi_transfer t;
-+
-+ spi_message_init(&msg);
-+ memset(&t, 0, sizeof t);
-+ t.len = sizeof(data);
-+ spi_message_add_tail(&t, &msg);
-+ t.tx_buf = &data[0];
-+ t.rx_buf = &data[0];
-+
-+ /* grab the set of register containing status and XYZ data */
-+
-+ local_irq_save(flags);
-+
-+ /* Should complete without blocking */
-+ if (spi_non_blocking_transfer(lis->spi, &msg) < 0)
-+ dev_err(lis->dev, "Error reading registers\n");
-+
-+ local_irq_restore(flags);
-+
-+ /*
-+ * at the minute the test below fails 50% of the time due to
-+ * a problem with level interrupts causing ISRs to get called twice.
-+ * This is a workaround for that, but actually this test is still
-+ * valid and the information can be used for overrrun stats.
-+ */
-+
-+ /* has any kind of overrun been observed by the lis302dl? */
-+ if (read[0] & (LIS302DL_STATUS_XOR |
-+ LIS302DL_STATUS_YOR |
-+ LIS302DL_STATUS_ZOR))
-+ lis->overruns++;
-+
-+ /* we have a valid sample set? */
-+ if (read[0] & LIS302DL_STATUS_XYZDA) {
-+ input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
-+ (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
-+ input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
-+ (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
-+ input_report_abs(lis->input_dev, ABS_Z, mg_per_sample *
-+ (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
-+
-+ input_sync(lis->input_dev);
-+ }
-+
-+ if (lis->threshold)
-+ /* acknowledge the wakeup source */
-+ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
-+}
-+
-+static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
-+{
-+ struct lis302dl_info *lis = _lis;
-+
-+ lis302dl_bitbang_read_sample(lis);
-+ return IRQ_HANDLED;
-+}
-+
-+/* sysfs */
-+
-+static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ return sprintf(buf, "%u\n", lis->overruns);
-+}
-+
-+static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL);
-+
-+static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ u8 ctrl1;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
-+ local_irq_restore(flags);
-+
-+ 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);
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+
-+ if (!strcmp(buf, "400\n")) {
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
-+ LIS302DL_CTRL1_DR);
-+ lis->flags |= LIS302DL_F_DR;
-+ } else {
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
-+ 0);
-+ lis->flags &= ~LIS302DL_F_DR;
-+ }
-+ local_irq_restore(flags);
-+
-+ 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;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
-+ local_irq_restore(flags);
-+
-+ 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);
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+
-+ if (!strcmp(buf, "9.2\n")) {
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
-+ LIS302DL_CTRL1_FS);
-+ lis->flags |= LIS302DL_F_FS;
-+ } else {
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
-+ 0);
-+ lis->flags &= ~LIS302DL_F_FS;
-+ }
-+
-+ if (lis->flags & LIS302DL_F_INPUT_OPEN)
-+ __enable_data_collection(lis);
-+
-+ local_irq_restore(flags);
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
-+
-+static ssize_t show_threshold(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ /* Display the device view of the threshold setting */
-+ return sprintf(buf, "%d\n", __threshold_to_mg(lis,
-+ __mg_to_threshold(lis, lis->threshold)));
-+}
-+
-+static ssize_t set_threshold(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ unsigned int val;
-+
-+ if (sscanf(buf, "%u\n", &val) != 1)
-+ return -EINVAL;
-+ /* 8g is the maximum if FS is 1 */
-+ if (val > 8000)
-+ return -ERANGE;
-+
-+ /* Set the threshold and write it out if the device is used */
-+ lis->threshold = val;
-+
-+ if (lis->flags & LIS302DL_F_INPUT_OPEN) {
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ __enable_data_collection(lis);
-+ local_irq_restore(flags);
-+ }
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold);
-+
-+static ssize_t show_duration(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ return sprintf(buf, "%d\n", __duration_to_ms(lis,
-+ __ms_to_duration(lis, lis->duration)));
-+}
-+
-+static ssize_t set_duration(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ unsigned int val;
-+
-+ if (sscanf(buf, "%u\n", &val) != 1)
-+ return -EINVAL;
-+ if (val > 2550)
-+ return -ERANGE;
-+
-+ lis->duration = val;
-+ if (lis->flags & LIS302DL_F_INPUT_OPEN)
-+ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
-+ __ms_to_duration(lis, lis->duration));
-+
-+ return count;
-+}
-+
-+static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration);
-+
-+static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ int n = 0;
-+ u8 reg[0x40];
-+ char *end = buf;
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+
-+ for (n = 0; n < sizeof(reg); n++)
-+ reg[n] = __reg_read(lis, n);
-+
-+ local_irq_restore(flags);
-+
-+ for (n = 0; n < sizeof(reg); n += 16) {
-+ hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
-+ end += strlen(end);
-+ *end++ = '\n';
-+ *end++ = '\0';
-+ }
-+
-+ return end - buf;
-+}
-+static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
-+
-+/* Configure freefall/wakeup interrupts */
-+static ssize_t set_wakeup_threshold(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ unsigned int threshold;
-+
-+ if (sscanf(buf, "%u\n", &threshold) != 1)
-+ return -EINVAL;
-+
-+ if (threshold > 8000)
-+ return -ERANGE;
-+
-+ /* Zero turns the feature off */
-+ if (threshold == 0) {
-+ if (lis->flags & LIS302DL_F_IRQ_WAKE) {
-+ disable_irq_wake(lis->pdata->interrupt);
-+ lis->flags &= ~LIS302DL_F_IRQ_WAKE;
-+ }
-+
-+ return count;
-+ }
-+
-+ lis->wakeup.threshold = threshold;
-+
-+ if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
-+ enable_irq_wake(lis->pdata->interrupt);
-+ lis->flags |= LIS302DL_F_IRQ_WAKE;
-+ }
-+
-+ return count;
-+}
-+
-+static ssize_t show_wakeup_threshold(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ /* All events off? */
-+ if (lis->wakeup.threshold == 0)
-+ return sprintf(buf, "off\n");
-+
-+ return sprintf(buf, "%u\n", lis->wakeup.threshold);
-+}
-+
-+static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold,
-+ set_wakeup_threshold);
-+
-+static ssize_t set_wakeup_duration(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t count)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+ unsigned int duration;
-+
-+ if (sscanf(buf, "%u\n", &duration) != 1)
-+ return -EINVAL;
-+
-+ if (duration > 2550)
-+ return -ERANGE;
-+
-+ lis->wakeup.duration = duration;
-+
-+ return count;
-+}
-+
-+static ssize_t show_wakeup_duration(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(dev);
-+
-+ return sprintf(buf, "%u\n", lis->wakeup.duration);
-+}
-+
-+static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration,
-+ set_wakeup_duration);
-+
-+static struct attribute *lis302dl_sysfs_entries[] = {
-+ &dev_attr_sample_rate.attr,
-+ &dev_attr_full_scale.attr,
-+ &dev_attr_threshold.attr,
-+ &dev_attr_duration.attr,
-+ &dev_attr_dump.attr,
-+ &dev_attr_wakeup_threshold.attr,
-+ &dev_attr_wakeup_duration.attr,
-+ &dev_attr_overruns.attr,
-+ NULL
-+};
-+
-+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 = input_get_drvdata(inp);
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+
-+ __enable_data_collection(lis);
-+ lis->flags |= LIS302DL_F_INPUT_OPEN;
-+
-+ local_irq_restore(flags);
-+
-+ return 0;
-+}
-+
-+static void lis302dl_input_close(struct input_dev *inp)
-+{
-+ struct lis302dl_info *lis = input_get_drvdata(inp);
-+ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
-+ LIS302DL_CTRL1_Zen;
-+ unsigned long flags;
-+
-+ local_irq_save(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
-+ * disable the data ready events */
-+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
-+ lis->flags &= ~LIS302DL_F_INPUT_OPEN;
-+
-+ /* 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);
-+ }
-+ local_irq_restore(flags);
-+}
-+
-+/* get the device to reload its coefficients from EEPROM and wait for it
-+ * to complete
-+ */
-+
-+static int __lis302dl_reset_device(struct lis302dl_info *lis)
-+{
-+ int timeout = 10;
-+
-+ __reg_write(lis, LIS302DL_REG_CTRL2,
-+ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
-+
-+ while ((__reg_read(lis, LIS302DL_REG_CTRL2)
-+ & LIS302DL_CTRL2_BOOT) && (timeout--))
-+ mdelay(1);
-+
-+ return !!(timeout < 0);
-+}
-+
-+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 = spi->dev.platform_data;
-+
-+ spi->mode = SPI_MODE_3;
-+ rc = spi_setup(spi);
-+ if (rc < 0) {
-+ dev_err(&spi->dev, "spi_setup failed\n");
-+ return rc;
-+ }
-+
-+ lis = kzalloc(sizeof(*lis), GFP_KERNEL);
-+ if (!lis)
-+ return -ENOMEM;
-+
-+ lis->dev = &spi->dev;
-+ lis->spi = spi;
-+
-+ dev_set_drvdata(lis->dev, lis);
-+
-+ lis->pdata = pdata;
-+
-+ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
-+ if (rc) {
-+ dev_err(lis->dev, "error creating sysfs group\n");
-+ goto bail_free_lis;
-+ }
-+
-+ /* initialize input layer details */
-+ lis->input_dev = input_allocate_device();
-+ if (!lis->input_dev) {
-+ dev_err(lis->dev, "Unable to allocate input device\n");
-+ goto bail_sysfs;
-+ }
-+
-+ input_set_drvdata(lis->input_dev, lis);
-+ 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;
-+
-+ rc = input_register_device(lis->input_dev);
-+ if (rc) {
-+ dev_err(lis->dev, "error %d registering input device\n", rc);
-+ goto bail_inp_dev;
-+ }
-+
-+ local_irq_save(flags);
-+ /* Configure our IO */
-+ (lis->pdata->lis302dl_suspend_io)(lis, 1);
-+
-+ wai = __reg_read(lis, LIS302DL_REG_WHO_AM_I);
-+ if (wai != LIS302DL_WHO_AM_I_MAGIC) {
-+ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
-+ dev_set_drvdata(lis->dev, NULL);
-+ rc = -ENODEV;
-+ local_irq_restore(flags);
-+ goto bail_inp_reg;
-+ }
-+
-+ set_bit(EV_ABS, lis->input_dev->evbit);
-+ input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0);
-+ input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0);
-+ input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0);
-+
-+
-+ lis->threshold = 0;
-+ lis->duration = 0;
-+ memset(&lis->wakeup, 0, sizeof(lis->wakeup));
-+
-+ if (__lis302dl_reset_device(lis))
-+ dev_err(lis->dev, "device BOOT reload failed\n");
-+
-+ /* force us powered */
-+ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
-+ LIS302DL_CTRL1_Xen |
-+ LIS302DL_CTRL1_Yen |
-+ LIS302DL_CTRL1_Zen);
-+ mdelay(1);
-+
-+ __reg_write(lis, LIS302DL_REG_CTRL2, 0);
-+ __reg_write(lis, LIS302DL_REG_CTRL3,
-+ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
-+ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0);
-+
-+ /* start off in powered down mode; we power up when someone opens us */
-+ __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(lis->dev, 1, LIS302DL_INTMODE_GND);
-+ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND);
-+
-+ __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);
-+ local_irq_restore(flags);
-+
-+ dev_info(lis->dev, "Found %s\n", pdata->name);
-+
-+ lis->pdata = pdata;
-+
-+ set_irq_handler(lis->pdata->interrupt, handle_level_irq);
-+
-+ rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt,
-+ IRQF_TRIGGER_LOW, "lis302dl", lis);
-+
-+ if (rc < 0) {
-+ dev_err(lis->dev, "error requesting IRQ %d\n",
-+ lis->pdata->interrupt);
-+ goto bail_inp_reg;
-+ }
-+ 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(&lis->dev->kobj, &lis302dl_attr_group);
-+bail_free_lis:
-+ kfree(lis);
-+ return rc;
-+}
-+
-+static int __devexit lis302dl_remove(struct spi_device *spi)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+ unsigned long flags;
-+
-+ /* Disable interrupts */
-+ if (lis->flags & LIS302DL_F_IRQ_WAKE)
-+ disable_irq_wake(lis->pdata->interrupt);
-+ free_irq(lis->pdata->interrupt, lis);
-+
-+ /* Reset and power down the device */
-+ local_irq_save(flags);
-+ __reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
-+ __reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
-+ __reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
-+ local_irq_restore(flags);
-+
-+ /* Cleanup resources */
-+ 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(lis->dev, NULL);
-+ kfree(lis);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static u8 regs_to_save[] = {
-+ LIS302DL_REG_CTRL2,
-+ LIS302DL_REG_CTRL3,
-+ LIS302DL_REG_FF_WU_CFG_1,
-+ LIS302DL_REG_FF_WU_THS_1,
-+ LIS302DL_REG_FF_WU_DURATION_1,
-+ LIS302DL_REG_FF_WU_CFG_2,
-+ LIS302DL_REG_FF_WU_THS_2,
-+ LIS302DL_REG_FF_WU_DURATION_2,
-+ LIS302DL_REG_CLICK_CFG,
-+ LIS302DL_REG_CLICK_THSY_X,
-+ LIS302DL_REG_CLICK_THSZ,
-+ LIS302DL_REG_CLICK_TIME_LIMIT,
-+ LIS302DL_REG_CLICK_LATENCY,
-+ LIS302DL_REG_CLICK_WINDOW,
-+ LIS302DL_REG_CTRL1,
-+};
-+
-+static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
-+{
-+ struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
-+ unsigned long flags;
-+ u_int8_t tmp;
-+ int n;
-+
-+ /* determine if we want to wake up from the accel. */
-+ if (lis->flags & LIS302DL_F_WUP_CLICK)
-+ return 0;
-+
-+ disable_irq(lis->pdata->interrupt);
-+ local_irq_save(flags);
-+
-+ /*
-+ * When we share SPI over multiple sensors, there is a race here
-+ * that one or more sensors will lose. In that case, the shared
-+ * SPI bus GPIO will be in sleep mode and partially pulled down. So
-+ * we explicitly put our IO into "wake" mode here before the final
-+ * traffic to the sensor.
-+ */
-+ (lis->pdata->lis302dl_suspend_io)(lis, 1);
-+
-+ /* save registers */
-+ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
-+ lis->regs[regs_to_save[n]] =
-+ __reg_read(lis, regs_to_save[n]);
-+
-+ /* power down or enable wakeup */
-+
-+ if (lis->wakeup.threshold == 0) {
-+ tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
-+ tmp &= ~LIS302DL_CTRL1_PD;
-+ __reg_write(lis, LIS302DL_REG_CTRL1, tmp);
-+ } else
-+ __enable_wakeup(lis);
-+
-+ /* place our IO to the device in sleep-compatible states */
-+ (lis->pdata->lis302dl_suspend_io)(lis, 0);
-+
-+ 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;
-+ int n;
-+
-+ if (lis->flags & LIS302DL_F_WUP_CLICK)
-+ return 0;
-+
-+ local_irq_save(flags);
-+
-+ /* get our IO to the device back in operational states */
-+ (lis->pdata->lis302dl_suspend_io)(lis, 1);
-+
-+ /* resume from powerdown first! */
-+ __reg_write(lis, LIS302DL_REG_CTRL1,
-+ LIS302DL_CTRL1_PD |
-+ LIS302DL_CTRL1_Xen |
-+ LIS302DL_CTRL1_Yen |
-+ LIS302DL_CTRL1_Zen);
-+ mdelay(1);
-+
-+ if (__lis302dl_reset_device(lis))
-+ dev_err(&spi->dev, "device BOOT reload failed\n");
-+
-+ /* restore registers after resume */
-+ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
-+ __reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]);
-+
-+ /* if someone had us open, reset the non-wake threshold stuff */
-+ if (lis->flags & LIS302DL_F_INPUT_OPEN)
-+ __enable_data_collection(lis);
-+
-+ local_irq_restore(flags);
-+ enable_irq(lis->pdata->interrupt);
-+
-+ return 0;
-+}
-+#else
-+#define lis302dl_suspend NULL
-+#define lis302dl_resume NULL
-+#endif
-+
-+static struct spi_driver lis302dl_spi_driver = {
-+ .driver = {
-+ .name = "lis302dl",
-+ .owner = THIS_MODULE,
-+ },
-+
-+ .probe = lis302dl_probe,
-+ .remove = __devexit_p(lis302dl_remove),
-+ .suspend = lis302dl_suspend,
-+ .resume = lis302dl_resume,
-+};
-+
-+static int __devinit lis302dl_init(void)
-+{
-+ return spi_register_driver(&lis302dl_spi_driver);
-+}
-+
-+static void __exit lis302dl_exit(void)
-+{
-+ spi_unregister_driver(&lis302dl_spi_driver);
-+}
-+
-+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
-+MODULE_LICENSE("GPL");
-+
-+module_init(lis302dl_init);
-+module_exit(lis302dl_exit);
-diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
-index 5265330..24c61a6 100644
---- a/drivers/spi/spi_bitbang.c
-+++ b/drivers/spi/spi_bitbang.c
-@@ -254,134 +254,139 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
- * Drivers can provide word-at-a-time i/o primitives, or provide
- * transfer-at-a-time ones to leverage dma or fifo hardware.
- */
--static void bitbang_work(struct work_struct *work)
-+/* Synchronous non blocking transfer */
-+int
-+spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m)
- {
-- struct spi_bitbang *bitbang =
-- container_of(work, struct spi_bitbang, work);
-- unsigned long flags;
-- int do_setup = -1;
-- int (*setup_transfer)(struct spi_device *,
-- struct spi_transfer *);
-+ struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
-+ struct spi_transfer *t;
-+ unsigned long flags;
-+ int cs_change = 1;
-+ int status;
-+ int nsecs;
-+ int (*setup_transfer)(struct spi_device *, struct spi_transfer *);
-+
-+ /* FIXME this is made-up ... the correct value is known to
-+ * word-at-a-time bitbang code, and presumably chipselect()
-+ * should enforce these requirements too?
-+ */
-+ nsecs = 100;
-+ cs_change = 1;
-+ status = 0;
-+ setup_transfer = NULL;
-+
-+ local_irq_save(flags);
-+ list_for_each_entry (t, &m->transfers, transfer_list) {
-+ /* override or restore speed and wordsize */
-+ if (t->speed_hz || t->bits_per_word) {
-+ setup_transfer = bitbang->setup_transfer;
-+ if (!setup_transfer) {
-+ status = -ENOPROTOOPT;
-+ break;
-+ }
-+ }
-+ if (setup_transfer) {
-+ status = setup_transfer(spi, t);
-+ if (status < 0)
-+ break;
-+ }
-
-- setup_transfer = bitbang->setup_transfer;
-+ /* set up default clock polarity, and activate chip;
-+ * this implicitly updates clock and spi modes as
-+ * previously recorded for this device via setup().
-+ * (and also deselects any other chip that might be
-+ * selected ...)
-+ */
-
-- spin_lock_irqsave(&bitbang->lock, flags);
-- bitbang->busy = 1;
-- while (!list_empty(&bitbang->queue)) {
-- struct spi_message *m;
-- struct spi_device *spi;
-- unsigned nsecs;
-- struct spi_transfer *t = NULL;
-- unsigned tmp;
-- unsigned cs_change;
-- int status;
-+ if (cs_change) {
-+ bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-+ ndelay(nsecs);
-+ }
-
-- m = container_of(bitbang->queue.next, struct spi_message,
-- queue);
-- list_del_init(&m->queue);
-- spin_unlock_irqrestore(&bitbang->lock, flags);
-+ cs_change = t->cs_change;
-+ if (!t->tx_buf && !t->rx_buf && t->len) {
-+ status = -EINVAL;
-+ break;
-+ }
-
-- /* FIXME this is made-up ... the correct value is known to
-- * word-at-a-time bitbang code, and presumably chipselect()
-- * should enforce these requirements too?
-+ /* transfer data. the lower level code handles any
-+ * new dma mappings it needs. our caller always gave
-+ * us dma-safe buffers.
- */
-- nsecs = 100;
-+ if (t->len) {
-+ /* REVISIT dma API still needs a designated
-+ * DMA_ADDR_INVALID; ~0 might be better.
-+ */
-+ if (!m->is_dma_mapped)
-+ t->rx_dma = t->tx_dma = 0;
-+ status = bitbang->txrx_bufs(spi, t);
-+ }
-
-- spi = m->spi;
-- tmp = 0;
-- cs_change = 1;
-+ if (status > 0)
-+ m->actual_length += status;
-+ if (status != t->len) {
-+ /* always report some kind of error */
-+ if (status >= 0)
-+ status = -EREMOTEIO;
-+ break;
-+ }
- status = 0;
-+ /* protocol tweaks before next transfer */
-+ if (t->delay_usecs)
-+ udelay(t->delay_usecs);
-+ if (!cs_change)
-+ continue;
-+ if (t->transfer_list.next == &m->transfers)
-+ break;
-+ /* sometimes a short mid-message deselect of the chip
-+ * may be needed to terminate a mode or command
-+ */
-+ ndelay(nsecs);
-+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-+ ndelay(nsecs);
-+ }
-
-- list_for_each_entry (t, &m->transfers, transfer_list) {
--
-- /* override speed or wordsize? */
-- if (t->speed_hz || t->bits_per_word)
-- do_setup = 1;
--
-- /* init (-1) or override (1) transfer params */
-- if (do_setup != 0) {
-- if (!setup_transfer) {
-- status = -ENOPROTOOPT;
-- break;
-- }
-- status = setup_transfer(spi, t);
-- if (status < 0)
-- break;
-- }
-+ m->status = status;
-+ if (m->complete)
-+ m->complete(m->context);
-
-- /* set up default clock polarity, and activate chip;
-- * this implicitly updates clock and spi modes as
-- * previously recorded for this device via setup().
-- * (and also deselects any other chip that might be
-- * selected ...)
-- */
-- if (cs_change) {
-- bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-- ndelay(nsecs);
-- }
-- cs_change = t->cs_change;
-- if (!t->tx_buf && !t->rx_buf && t->len) {
-- status = -EINVAL;
-- break;
-- }
-+ /* restore speed and wordsize */
-+ if (setup_transfer)
-+ setup_transfer(spi, NULL);
-
-- /* transfer data. the lower level code handles any
-- * new dma mappings it needs. our caller always gave
-- * us dma-safe buffers.
-- */
-- if (t->len) {
-- /* REVISIT dma API still needs a designated
-- * DMA_ADDR_INVALID; ~0 might be better.
-- */
-- if (!m->is_dma_mapped)
-- t->rx_dma = t->tx_dma = 0;
-- status = bitbang->txrx_bufs(spi, t);
-- }
-- if (status > 0)
-- m->actual_length += status;
-- if (status != t->len) {
-- /* always report some kind of error */
-- if (status >= 0)
-- status = -EREMOTEIO;
-- break;
-- }
-- status = 0;
--
-- /* protocol tweaks before next transfer */
-- if (t->delay_usecs)
-- udelay(t->delay_usecs);
-+ /* normally deactivate chipselect ... unless no error and
-+ * cs_change has hinted that the next message will probably
-+ * be for this chip too.
-+ */
-+ if (!(status == 0 && cs_change)) {
-+ ndelay(nsecs);
-+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-+ ndelay(nsecs);
-+ }
-
-- if (!cs_change)
-- continue;
-- if (t->transfer_list.next == &m->transfers)
-- break;
-+ local_irq_restore(flags);
-
-- /* sometimes a short mid-message deselect of the chip
-- * may be needed to terminate a mode or command
-- */
-- ndelay(nsecs);
-- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-- ndelay(nsecs);
-- }
-+ return status;
-+}
-+EXPORT_SYMBOL_GPL(spi_bitbang_transfer_sync);
-
-- m->status = status;
-- m->complete(m->context);
-+static void bitbang_work(struct work_struct *work)
-+{
-+ struct spi_bitbang *bitbang =
-+ container_of(work, struct spi_bitbang, work);
-+ unsigned long flags;
-
-- /* restore speed and wordsize if it was overridden */
-- if (do_setup == 1)
-- setup_transfer(spi, NULL);
-- do_setup = 0;
-+ spin_lock_irqsave(&bitbang->lock, flags);
-+ bitbang->busy = 1;
-+ while (!list_empty(&bitbang->queue)) {
-+ struct spi_message *m;
-
-- /* normally deactivate chipselect ... unless no error and
-- * cs_change has hinted that the next message will probably
-- * be for this chip too.
-- */
-- if (!(status == 0 && cs_change)) {
-- ndelay(nsecs);
-- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-- ndelay(nsecs);
-- }
-+ m = container_of(bitbang->queue.next, struct spi_message,
-+ queue);
-+ list_del_init(&m->queue);
-
-+ spin_unlock_irqrestore(&bitbang->lock, flags);
-+ spi_bitbang_transfer_sync(m->spi, m);
- spin_lock_irqsave(&bitbang->lock, flags);
- }
- bitbang->busy = 0;
-@@ -456,6 +461,10 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
-
- if (!bitbang->master->transfer)
- bitbang->master->transfer = spi_bitbang_transfer;
-+
-+ if (!bitbang->master->transfer_sync && bitbang->non_blocking_transfer)
-+ bitbang->master->transfer_sync = spi_bitbang_transfer_sync;
-+
- if (!bitbang->txrx_bufs) {
- bitbang->use_dma = 0;
- bitbang->txrx_bufs = spi_bitbang_bufs;
-diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
-index bbf9371..5685b78 100644
---- a/drivers/spi/spi_s3c24xx_gpio.c
-+++ b/drivers/spi/spi_s3c24xx_gpio.c
-@@ -92,7 +92,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)
-@@ -113,14 +113,17 @@ 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;
- sp->bitbang.master->num_chipselect = info->num_chipselect;
- sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
-+ sp->bitbang.non_blocking_transfer = info->non_blocking_transfer;
-
- sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
- sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
-diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
-new file mode 100644
-index 0000000..0c1fc30
---- /dev/null
-+++ b/include/linux/lis302dl.h
-@@ -0,0 +1,152 @@
-+#ifndef _LINUX_LIS302DL_H
-+#define _LINUX_LIS302DL_H
-+
-+#include <linux/types.h>
-+#include <linux/spi/spi.h>
-+#include <linux/input.h>
-+#include <linux/workqueue.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;
-+ int interrupt;
-+ void (*lis302dl_suspend_io)(struct lis302dl_info *, int resuming);
-+};
-+
-+struct lis302dl_info {
-+ struct lis302dl_platform_data *pdata;
-+ struct device *dev;
-+ struct input_dev *input_dev;
-+ unsigned int flags;
-+ unsigned int threshold;
-+ unsigned int duration;
-+ u32 overruns;
-+ struct {
-+ unsigned int threshold; /* mg */
-+ unsigned int duration; /* ms */
-+ } wakeup;
-+
-+ struct spi_device *spi;
-+ 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_ctrl2 {
-+ LIS302DL_CTRL2_HPC1 = 0x01,
-+ LIS302DL_CTRL2_HPC2 = 0x02,
-+ LIS302DL_CTRL2_HPFF1 = 0x04,
-+ LIS302DL_CTRL2_HPFF2 = 0x08,
-+ LIS302DL_CTRL2_FDS = 0x10,
-+ LIS302DL_CTRL2_BOOT = 0x40,
-+ LIS302DL_CTRL2_SIM = 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,
-+};
-+
-+/* Wakeup/freefall interrupt defs */
-+enum lis302dl_reg_ffwucfg {
-+ LIS302DL_FFWUCFG_XLIE = 0x01,
-+ LIS302DL_FFWUCFG_XHIE = 0x02,
-+ LIS302DL_FFWUCFG_YLIE = 0x04,
-+ LIS302DL_FFWUCFG_YHIE = 0x08,
-+ LIS302DL_FFWUCFG_ZLIE = 0x10,
-+ LIS302DL_FFWUCFG_ZHIE = 0x20,
-+ LIS302DL_FFWUCFG_LIR = 0x40,
-+ LIS302DL_FFWUCFG_AOI = 0x80,
-+};
-+
-+enum lis302dl_reg_ffwuths {
-+ LIS302DL_FFWUTHS_DCRM = 0x80,
-+};
-+
-+enum lis302dl_reg_ffwusrc {
-+ LIS302DL_FFWUSRC_XL = 0x01,
-+ LIS302DL_FFWUSRC_XH = 0x02,
-+ LIS302DL_FFWUSRC_YL = 0x04,
-+ LIS302DL_FFWUSRC_YH = 0x08,
-+ LIS302DL_FFWUSRC_ZL = 0x10,
-+ LIS302DL_FFWUSRC_ZH = 0x20,
-+ LIS302DL_FFWUSRC_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_1 0x0001 /* wake up from free fall */
-+#define LIS302DL_F_WUP_FF_2 0x0002
-+#define LIS302DL_F_WUP_FF 0x0003
-+#define LIS302DL_F_WUP_CLICK 0x0004
-+#define LIS302DL_F_POWER 0x0010
-+#define LIS302DL_F_FS 0x0020 /* ADC full scale */
-+#define LIS302DL_F_INPUT_OPEN 0x0040 /* Set if input device is opened */
-+#define LIS302DL_F_IRQ_WAKE 0x0080 /* IRQ is setup in wake mode */
-+#define LIS302DL_F_DR 0x0100 /* Data rate, 400Hz/100Hz */
-+
-+
-+#endif /* _LINUX_LIS302DL_H */
-+
-diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
-index af56071..83ad05d 100644
---- a/include/linux/spi/spi.h
-+++ b/include/linux/spi/spi.h
-@@ -292,6 +292,13 @@ struct spi_master {
- int (*transfer)(struct spi_device *spi,
- struct spi_message *mesg);
-
-+ /*
-+ * Synchronous non blocking transfer function. Should guarantee
-+ * data availability when it returns
-+ */
-+ int (*transfer_sync)(struct spi_device *spi,
-+ struct spi_message *mesg);
-+
- /* called on release() to free memory provided by spi_master */
- void (*cleanup)(struct spi_device *spi);
- };
-@@ -543,6 +550,29 @@ static inline void spi_message_free(struct spi_message *m)
- extern int spi_setup(struct spi_device *spi);
- extern int spi_async(struct spi_device *spi, struct spi_message *message);
-
-+/**
-+ * spi_non_blocking_transfer - Synchronous, non blocking transfer
-+ * @spi: device with which data will be exchanged
-+ * @message: describes the data transfers with optional completion handlers
-+ * Context: any (irqs may be blocked, etc)
-+ *
-+ * Data is guaranteed to be written or read when this function returns.
-+ *
-+ * Note : This may not be supported by all spi masters.
-+ */
-+
-+static inline int
-+spi_non_blocking_transfer(struct spi_device *spi, struct spi_message *message)
-+{
-+ if (unlikely(!spi->master->transfer_sync)) {
-+ dev_err(&spi->master->dev,
-+ "non-blocking transfers not supported\n");
-+ return -EIO;
-+ }
-+
-+ return spi->master->transfer_sync(spi, message);
-+}
-+
- /*---------------------------------------------------------------------------*/
-
- /* All these synchronous SPI transfer routines are utilities layered
-diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
-index 3274c50..6dc9b8b 100644
---- a/include/linux/spi/spi_bitbang.h
-+++ b/include/linux/spi/spi_bitbang.h
-@@ -31,6 +31,9 @@ struct spi_bitbang {
- u8 use_dma;
- u8 flags; /* extra spi->mode support */
-
-+ /* Support for synchronous non blocking transfers */
-+ int non_blocking_transfer;
-+
- struct spi_master *master;
-
- /* setup_transfer() changes clock and/or wordsize to match settings
-@@ -62,6 +65,8 @@ extern void spi_bitbang_cleanup(struct spi_device *spi);
- extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
- extern int spi_bitbang_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t);
-+extern int spi_bitbang_transfer_sync(struct spi_device *spi,
-+ struct spi_message *m);
-
- /* start or stop queue processing */
- extern int spi_bitbang_start(struct spi_bitbang *spi);
---
-1.7.3
-