mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-28 14:57:31 +02:00
fc54b9bf15
(stable-branch of Openmoko) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@13613 3c298f89-4303-0410-b956-a3cf2f4a3e73
1185 lines
38 KiB
Diff
1185 lines
38 KiB
Diff
From 1c6f5a92c816db43128444606c26507ebe6e5a43 Mon Sep 17 00:00:00 2001
|
|
From: Andy Green <andy@openmoko.com>
|
|
Date: Mon, 13 Oct 2008 12:01:05 +0100
|
|
Subject: [PATCH] fix-lid302dl-bitbang-all-the-way-baby.patch
|
|
|
|
This large patch removes motion sensor from Linux SPI bitbang driver.
|
|
Previously, some access was done through Linux SPI protected
|
|
by a mutex, and the ISR access was done by platform bitbang code due
|
|
to inability of Linux SPI driver to work in the interrupt context.
|
|
|
|
Now all access is done by bitbang callbacks in mach_gta02.c and are
|
|
protected by single scheme of interrupt lockout for the duration --
|
|
I line-by-line'd the driver to confirm that best I could, adding
|
|
protection and taking more care on several /sys related paths.
|
|
|
|
Because this is no longer a Linux SPI bus driver, the path for various
|
|
/sys things have changed. They can now be found down, eg,
|
|
|
|
/sys/devices/platform/lis302dl.1/sample_rate
|
|
|
|
lis302dl.1 is the top sensor and .2 the bottom. The names of the input
|
|
susbsytem paths remain the same as before.
|
|
|
|
Signed-off-by: Andy Green <andy@openmoko.com>
|
|
---
|
|
arch/arm/mach-s3c2440/mach-gta02.c | 233 +++++++++----------
|
|
drivers/input/misc/lis302dl.c | 437 ++++++++++++++++--------------------
|
|
include/linux/lis302dl.h | 9 +-
|
|
3 files changed, 315 insertions(+), 364 deletions(-)
|
|
|
|
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
index 467c417..b19632c 100644
|
|
--- a/arch/arm/mach-s3c2440/mach-gta02.c
|
|
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
@@ -1052,20 +1052,21 @@ static struct platform_device gta02_vibrator_dev = {
|
|
/* #define DEBUG_SPEW_MS */
|
|
#define MG_PER_SAMPLE 18
|
|
|
|
-struct lis302dl_platform_data lis302_pdata[];
|
|
+struct lis302dl_platform_data lis302_pdata_top;
|
|
+struct lis302dl_platform_data lis302_pdata_bottom;
|
|
|
|
-void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
|
|
+/*
|
|
+ * generic SPI RX and TX bitbang
|
|
+ * only call with interrupts off!
|
|
+ */
|
|
+
|
|
+static void __gta02_lis302dl_bitbang(struct lis302dl_info *lis, u8 *tx,
|
|
+ int tx_bytes, u8 *rx, int rx_bytes)
|
|
{
|
|
struct lis302dl_platform_data *pdata = lis->pdata;
|
|
- u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
|
|
- int n, n1;
|
|
+ int n;
|
|
+ u8 shifter = 0;
|
|
unsigned long other_cs;
|
|
- unsigned long flags;
|
|
-#ifdef DEBUG_SPEW_MS
|
|
- s8 x, y, z;
|
|
-#endif
|
|
-
|
|
- local_irq_save(flags);
|
|
|
|
/*
|
|
* Huh.. "quirk"... CS on this device is not really "CS" like you can
|
|
@@ -1073,20 +1074,25 @@ void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
|
|
* have 2 devices on one interface, the "disabled" device when we talk
|
|
* to an "enabled" device sees the clocks as I2C clocks, creating
|
|
* havoc.
|
|
+ *
|
|
* I2C sees MOSI going LOW while CLK HIGH as a START action, we must
|
|
* ensure this is never issued.
|
|
*/
|
|
|
|
- if (&lis302_pdata[0] == pdata)
|
|
- other_cs = lis302_pdata[1].pin_chip_select;
|
|
+ if (&lis302_pdata_top == pdata)
|
|
+ other_cs = lis302_pdata_bottom.pin_chip_select;
|
|
else
|
|
- other_cs = lis302_pdata[0].pin_chip_select;
|
|
+ other_cs = lis302_pdata_top.pin_chip_select;
|
|
|
|
s3c2410_gpio_setpin(other_cs, 1);
|
|
s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
|
|
s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
|
s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
|
|
- for (n = 0; n < 8; n++) { /* write the r/w, inc and address */
|
|
+
|
|
+ /* send the register index, r/w and autoinc bits */
|
|
+ for (n = 0; n < (tx_bytes << 3); n++) {
|
|
+ if (!(n & 7))
|
|
+ shifter = tx[n >> 3];
|
|
s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
|
s3c2410_gpio_setpin(pdata->pin_mosi, (shifter >> 7) & 1);
|
|
s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
|
@@ -1095,44 +1101,71 @@ void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
|
|
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, 0);
|
|
- shifter <<= 1;
|
|
- if (s3c2410_gpio_getpin(pdata->pin_miso))
|
|
- shifter |= 1;
|
|
- s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
|
- s3c2410_gpio_setpin(pdata->pin_clk, 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;
|
|
- }
|
|
+ for (n = 0; n < (rx_bytes << 3); n++) { /* 8 bits each */
|
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
|
+ shifter <<= 1;
|
|
+ if (s3c2410_gpio_getpin(pdata->pin_miso))
|
|
+ shifter |= 1;
|
|
+ if ((n & 7) == 7)
|
|
+ rx[n >> 3] = shifter;
|
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
|
}
|
|
s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
|
|
s3c2410_gpio_setpin(other_cs, 1);
|
|
+}
|
|
+
|
|
+
|
|
+static int gta02_lis302dl_bitbang_read_reg(struct lis302dl_info *lis, u8 reg)
|
|
+{
|
|
+ u8 data = 0xc0 | reg; /* read, autoincrement */
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+
|
|
+ __gta02_lis302dl_bitbang(lis, &data, 1, &data, 1);
|
|
+
|
|
+ local_irq_restore(flags);
|
|
+
|
|
+ return data;
|
|
+}
|
|
+
|
|
+static void gta02_lis302dl_bitbang_write_reg(struct lis302dl_info *lis, u8 reg,
|
|
+ u8 val)
|
|
+{
|
|
+ u8 data[2] = { 0x00 | reg, val }; /* write, no autoincrement */
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+
|
|
+ __gta02_lis302dl_bitbang(lis, &data[0], 2, NULL, 0);
|
|
+
|
|
local_irq_restore(flags);
|
|
|
|
+}
|
|
+
|
|
+
|
|
+static void gta02_lis302dl_bitbang_sample(struct lis302dl_info *lis)
|
|
+{
|
|
+ u8 data = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
|
|
+ u8 read[5];
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+
|
|
+ __gta02_lis302dl_bitbang(lis, &data, 1, &read[0], 5);
|
|
+
|
|
+ local_irq_restore(flags);
|
|
+
|
|
+ input_report_rel(lis->input_dev, REL_X, MG_PER_SAMPLE * (s8)read[0]);
|
|
+ input_report_rel(lis->input_dev, REL_Y, MG_PER_SAMPLE * (s8)read[2]);
|
|
+ input_report_rel(lis->input_dev, REL_Z, MG_PER_SAMPLE * (s8)read[4]);
|
|
+
|
|
input_sync(lis->input_dev);
|
|
#ifdef DEBUG_SPEW_MS
|
|
- printk("%s: %d %d %d\n", pdata->name, x, y, z);
|
|
+ printk(KERN_INFO "%s: %d %d %d\n", pdata->name, read[0], read[2],
|
|
+ read[4]);
|
|
#endif
|
|
}
|
|
|
|
@@ -1159,103 +1192,58 @@ void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
|
|
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[] = {
|
|
- {
|
|
+
|
|
+
|
|
+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_bitbang_read = gta02_lis302dl_bitbang_read,
|
|
+ .lis302dl_bitbang_read_sample = gta02_lis302dl_bitbang_sample,
|
|
+ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
|
|
+ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
|
|
.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_bitbang_read = gta02_lis302dl_bitbang_read,
|
|
+ .lis302dl_bitbang_read_sample = gta02_lis302dl_bitbang_sample,
|
|
+ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
|
|
+ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
|
|
.lis302dl_suspend_io = gta02_lis302dl_suspend_io,
|
|
- },
|
|
};
|
|
|
|
-static struct spi_board_info gta02_spi_acc_bdinfo[] = {
|
|
- {
|
|
- .modalias = "lis302dl",
|
|
- .platform_data = &lis302_pdata[0],
|
|
- .irq = GTA02_IRQ_GSENSOR_1,
|
|
- .max_speed_hz = 10 * 1000 * 1000,
|
|
- .bus_num = 1,
|
|
- .chip_select = 0,
|
|
- .mode = SPI_MODE_3,
|
|
- },
|
|
- {
|
|
- .modalias = "lis302dl",
|
|
- .platform_data = &lis302_pdata[1],
|
|
- .irq = GTA02_IRQ_GSENSOR_2,
|
|
- .max_speed_hz = 10 * 1000 * 1000,
|
|
- .bus_num = 1,
|
|
- .chip_select = 1,
|
|
- .mode = SPI_MODE_3,
|
|
- },
|
|
-};
|
|
-
|
|
-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_acc1 = {
|
|
+ .name = "lis302dl",
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &lis302_pdata_top,
|
|
},
|
|
};
|
|
|
|
-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,
|
|
+static struct platform_device s3c_device_spi_acc2 = {
|
|
+ .name = "lis302dl",
|
|
+ .id = 2,
|
|
.dev = {
|
|
- .platform_data = &spi_gpio_cfg,
|
|
+ .platform_data = &lis302_pdata_bottom,
|
|
},
|
|
};
|
|
|
|
@@ -1573,8 +1561,8 @@ static void __init gta02_machine_init(void)
|
|
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;
|
|
+ lis302_pdata_top.open_drain = 0;
|
|
+ lis302_pdata_bottom.open_drain = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -1635,7 +1623,8 @@ static void __init gta02_machine_init(void)
|
|
mangle_glamo_res_by_system_rev();
|
|
platform_device_register(>a02_glamo_dev);
|
|
|
|
- platform_device_register(&s3c_device_spi_acc);
|
|
+ platform_device_register(&s3c_device_spi_acc1);
|
|
+ platform_device_register(&s3c_device_spi_acc2);
|
|
platform_device_register(>a02_button_dev);
|
|
platform_device_register(>a02_pm_gsm_dev);
|
|
platform_device_register(>a02_pm_usbhost_dev);
|
|
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
|
|
index b01ca04..1d5781d 100644
|
|
--- a/drivers/input/misc/lis302dl.c
|
|
+++ b/drivers/input/misc/lis302dl.c
|
|
@@ -1,7 +1,9 @@
|
|
/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
|
|
*
|
|
- * Copyright (C) 2007 by Openmoko, Inc.
|
|
+ * Copyright (C) 2007-2008 by Openmoko, Inc.
|
|
* Author: Harald Welte <laforge@openmoko.org>
|
|
+ * converted to private bitbang by:
|
|
+ * Andy Green <andy@openmoko.com>
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -39,78 +41,19 @@
|
|
|
|
#include <linux/lis302dl.h>
|
|
|
|
-/* lowlevel register access functions */
|
|
|
|
-#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)
|
|
+static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
|
|
+ u8 val)
|
|
{
|
|
- int rc;
|
|
- u_int8_t cmd;
|
|
-
|
|
- BUG_ON(reg & ~ADDR_MASK);
|
|
-
|
|
- cmd = reg | READ_BIT;
|
|
-
|
|
- rc = spi_w8r8(lis->spi_dev, cmd);
|
|
-
|
|
- return rc;
|
|
-}
|
|
-
|
|
-static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
|
|
-{
|
|
- u_int8_t ret;
|
|
-
|
|
- mutex_lock(&lis->lock);
|
|
- ret = __reg_read(lis, reg);
|
|
- mutex_unlock(&lis->lock);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
|
|
-{
|
|
- u_int8_t buf[2];
|
|
-
|
|
- BUG_ON(reg & ~ADDR_MASK);
|
|
-
|
|
- buf[0] = reg;
|
|
- buf[1] = val;
|
|
-
|
|
- return spi_write(lis->spi_dev, buf, sizeof(buf));
|
|
-}
|
|
-
|
|
-static int reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- mutex_lock(&lis->lock);
|
|
- ret = __reg_write(lis, reg, val);
|
|
- mutex_unlock(&lis->lock);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static int reg_set_bit_mask(struct lis302dl_info *lis,
|
|
- u_int8_t reg, u_int8_t mask, u_int8_t val)
|
|
-{
|
|
- int ret;
|
|
u_int8_t tmp;
|
|
|
|
val &= mask;
|
|
|
|
- mutex_lock(&lis->lock);
|
|
-
|
|
- tmp = __reg_read(lis, reg);
|
|
+ tmp = (lis->pdata->lis302dl_bitbang_reg_read)(lis, reg);
|
|
tmp &= ~mask;
|
|
tmp |= val;
|
|
- ret = __reg_write(lis, reg, tmp);
|
|
-
|
|
- mutex_unlock(&lis->lock);
|
|
-
|
|
- return ret;
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, reg, tmp);
|
|
}
|
|
|
|
/* interrupt handling related */
|
|
@@ -124,17 +67,17 @@ enum lis302dl_intmode {
|
|
LIS302DL_INTMODE_CLICK = 0x07,
|
|
};
|
|
|
|
-static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
|
|
+static void __lis302dl_int_mode(struct device *dev, int int_pin,
|
|
enum lis302dl_intmode mode)
|
|
{
|
|
- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
|
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
|
|
|
|
switch (int_pin) {
|
|
case 1:
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
|
|
break;
|
|
case 2:
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
|
|
break;
|
|
default:
|
|
BUG();
|
|
@@ -165,7 +108,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
|
|
{
|
|
struct lis302dl_info *lis = _lis;
|
|
|
|
- (lis->pdata->lis302dl_bitbang_read)(lis);
|
|
+ (lis->pdata->lis302dl_bitbang_read_sample)(lis);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -175,7 +118,13 @@ static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
|
- u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
+ u8 ctrl1;
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ ctrl1 = (lis->pdata->lis302dl_bitbang_reg_read)
|
|
+ (lis, LIS302DL_REG_CTRL1);
|
|
+ local_irq_restore(flags);
|
|
|
|
return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
|
|
}
|
|
@@ -184,12 +133,17 @@ 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,
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
|
|
LIS302DL_CTRL1_DR);
|
|
else
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, 0);
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
|
|
+ 0);
|
|
+ local_irq_restore(flags);
|
|
|
|
return count;
|
|
}
|
|
@@ -200,7 +154,13 @@ static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
|
- u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
+ u_int8_t ctrl1;
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ ctrl1 = (lis->pdata->lis302dl_bitbang_reg_read)(lis,
|
|
+ LIS302DL_REG_CTRL1);
|
|
+ local_irq_restore(flags);
|
|
|
|
return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
|
|
}
|
|
@@ -209,12 +169,18 @@ 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,
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
|
|
LIS302DL_CTRL1_FS);
|
|
else
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, 0);
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
|
|
+ 0);
|
|
+
|
|
+ local_irq_restore(flags);
|
|
|
|
return count;
|
|
}
|
|
@@ -222,7 +188,7 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
|
|
static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
|
|
|
|
static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
|
|
- char *buf)
|
|
+ char *buf)
|
|
{
|
|
struct lis302dl_info *lis = dev_get_drvdata(dev);
|
|
int n = 0;
|
|
@@ -233,7 +199,7 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
|
|
local_irq_save(flags);
|
|
|
|
for (n = 0; n < sizeof(reg); n++)
|
|
- reg[n] = reg_read(lis, n);
|
|
+ reg[n] = (lis->pdata->lis302dl_bitbang_reg_read)(lis, n);
|
|
|
|
local_irq_restore(flags);
|
|
|
|
@@ -248,9 +214,9 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
|
|
}
|
|
static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
|
|
|
|
-static int freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
|
|
+static int __freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
|
|
{
|
|
- u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
+ u8 r = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
|
|
|
|
/* If we have 400 ms sampling rate, the stepping is 2.5 ms,
|
|
* on 100 ms the stepping is 10ms */
|
|
@@ -268,9 +234,9 @@ static int freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
|
|
return ms / 10;
|
|
}
|
|
|
|
-static int freefall_duration_to_ms(struct lis302dl_info *lis, int duration)
|
|
+static int __freefall_duration_to_ms(struct lis302dl_info *lis, int duration)
|
|
{
|
|
- u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
+ u8 r = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
|
|
|
|
if (r & LIS302DL_CTRL1_DR)
|
|
return (duration * 25) / 10;
|
|
@@ -314,18 +280,18 @@ static ssize_t set_freefall_common(int which, struct device *dev,
|
|
/* Turn off the interrupt */
|
|
local_irq_save(flags);
|
|
if (lis->flags & LIS302DL_F_IRQ_WAKE)
|
|
- disable_irq_wake(lis->spi_dev->irq);
|
|
- lis302dl_int_mode(lis->spi_dev, which,
|
|
+ disable_irq_wake(lis->pdata->interrupt);
|
|
+ __lis302dl_int_mode(lis->dev, which,
|
|
LIS302DL_INTMODE_DATA_READY);
|
|
lis->flags &= ~(flag_mask | LIS302DL_F_IRQ_WAKE);
|
|
|
|
- reg_write(lis, r_cfg, 0);
|
|
- reg_write(lis, r_ths, 0);
|
|
- reg_write(lis, r_duration, 0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg, 0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_ths, 0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_duration, 0);
|
|
|
|
/* Power off unless the input subsystem is using the device */
|
|
if (!(lis->flags & LIS302DL_F_INPUT_OPEN))
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
|
|
LIS302DL_CTRL1_PD, 0);
|
|
|
|
local_irq_restore(flags);
|
|
@@ -337,7 +303,10 @@ static ssize_t set_freefall_common(int which, struct device *dev,
|
|
&and_events) != 6)
|
|
return -EINVAL;
|
|
|
|
- duration = freefall_ms_to_duration(lis, ms);
|
|
+ local_irq_save(flags);
|
|
+ duration = __freefall_ms_to_duration(lis, ms);
|
|
+ local_irq_save(flags);
|
|
+
|
|
if (duration < 0)
|
|
return -ERANGE;
|
|
|
|
@@ -355,23 +324,25 @@ static ssize_t set_freefall_common(int which, struct device *dev,
|
|
|
|
/* Setup the configuration registers */
|
|
local_irq_save(flags);
|
|
- reg_write(lis, r_cfg, 0); /* First zero to get to a known state */
|
|
- reg_write(lis, r_cfg,
|
|
+ /* First zero to get to a known state */
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg, 0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg,
|
|
(and_events ? LIS302DL_FFWUCFG_AOI : 0) |
|
|
x_lo | x_hi | y_lo | y_hi | z_lo | z_hi);
|
|
- reg_write(lis, r_ths, threshold & ~LIS302DL_FFWUTHS_DCRM);
|
|
- reg_write(lis, r_duration, duration);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_ths,
|
|
+ threshold & ~LIS302DL_FFWUTHS_DCRM);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_duration, duration);
|
|
|
|
/* Route the interrupt for wakeup */
|
|
- lis302dl_int_mode(lis->spi_dev, which, intmode);
|
|
+ __lis302dl_int_mode(lis->dev, which, intmode);
|
|
|
|
/* Power up the device and note that we want to wake up from
|
|
* this interrupt */
|
|
if (!(lis->flags & LIS302DL_F_IRQ_WAKE))
|
|
- enable_irq_wake(lis->spi_dev->irq);
|
|
+ enable_irq_wake(lis->pdata->interrupt);
|
|
|
|
lis->flags |= flag_mask | LIS302DL_F_IRQ_WAKE;
|
|
- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
|
|
LIS302DL_CTRL1_PD);
|
|
local_irq_restore(flags);
|
|
|
|
@@ -403,6 +374,8 @@ static ssize_t show_freefall_common(int which, struct device *dev,
|
|
int r_duration = LIS302DL_REG_FF_WU_DURATION_1;
|
|
int r_cfg = LIS302DL_REG_FF_WU_CFG_1;
|
|
int r_src = LIS302DL_REG_FF_WU_SRC_1;
|
|
+ unsigned long flags;
|
|
+ int ms;
|
|
|
|
/* Configure second freefall/wakeup pin */
|
|
if (which == 2) {
|
|
@@ -411,11 +384,15 @@ static ssize_t show_freefall_common(int which, struct device *dev,
|
|
r_cfg = LIS302DL_REG_FF_WU_CFG_2;
|
|
r_src = LIS302DL_REG_FF_WU_SRC_2;
|
|
}
|
|
- config = reg_read(lis, r_cfg);
|
|
- threshold = reg_read(lis, r_ths);
|
|
- duration = reg_read(lis, r_duration);
|
|
- r4 = reg_read(lis, r_src);
|
|
- r5 = reg_read(lis, LIS302DL_REG_CTRL3);
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ config = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_cfg);
|
|
+ threshold = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_ths);
|
|
+ duration = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_duration);
|
|
+ r4 = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_src);
|
|
+ r5 = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL3);
|
|
+ ms = __freefall_duration_to_ms(lis, duration);
|
|
+ local_irq_restore(flags);
|
|
|
|
/* All events off? */
|
|
if ((config & (LIS302DL_FFWUCFG_XLIE | LIS302DL_FFWUCFG_XHIE |
|
|
@@ -423,13 +400,14 @@ static ssize_t show_freefall_common(int which, struct device *dev,
|
|
LIS302DL_FFWUCFG_ZLIE | LIS302DL_FFWUCFG_ZHIE)) == 0)
|
|
return sprintf(buf, "off\n");
|
|
|
|
+
|
|
return sprintf(buf,
|
|
"%s events, %s interrupt, duration %d, threshold %d, "
|
|
"enabled: %s %s %s %s %s %s\n",
|
|
(config & LIS302DL_FFWUCFG_AOI) == 0 ? "or" : "and",
|
|
(config & LIS302DL_FFWUCFG_LIR) == 0 ?
|
|
"don't latch" : "latch",
|
|
- freefall_duration_to_ms(lis, duration), threshold,
|
|
+ ms, threshold,
|
|
(config & LIS302DL_FFWUCFG_XLIE) == 0 ? "---" : "xlo",
|
|
(config & LIS302DL_FFWUCFG_XHIE) == 0 ? "---" : "xhi",
|
|
(config & LIS302DL_FFWUCFG_YLIE) == 0 ? "---" : "ylo",
|
|
@@ -480,14 +458,15 @@ static int lis302dl_input_open(struct input_dev *inp)
|
|
|
|
local_irq_save(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);
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
|
|
|
|
lis->flags |= LIS302DL_F_INPUT_OPEN;
|
|
|
|
/* 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);
|
|
+ (lis->pdata->lis302dl_bitbang_read_sample)(lis);
|
|
+
|
|
+ local_irq_restore(flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -504,13 +483,13 @@ static void lis302dl_input_close(struct input_dev *inp)
|
|
/* 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);
|
|
+ __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,
|
|
+ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
|
|
0x00);
|
|
}
|
|
local_irq_restore(flags);
|
|
@@ -524,23 +503,23 @@ static int __lis302dl_reset_device(struct lis302dl_info *lis)
|
|
{
|
|
int timeout = 10;
|
|
|
|
- reg_write(lis, LIS302DL_REG_CTRL2, LIS302DL_CTRL2_BOOT |
|
|
- LIS302DL_CTRL2_FDS);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2,
|
|
+ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
|
|
|
|
- while ((reg_read(lis, LIS302DL_REG_CTRL2) & LIS302DL_CTRL2_BOOT) &&
|
|
- (timeout--))
|
|
+ while (((lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL2)
|
|
+ & LIS302DL_CTRL2_BOOT) && (timeout--))
|
|
mdelay(1);
|
|
|
|
return !!(timeout < 0);
|
|
}
|
|
|
|
-static int __devinit lis302dl_probe(struct spi_device *spi)
|
|
+static int __devinit lis302dl_probe(struct platform_device *pdev)
|
|
{
|
|
int rc;
|
|
struct lis302dl_info *lis;
|
|
u_int8_t wai;
|
|
unsigned long flags;
|
|
- struct lis302dl_platform_data *pdata;
|
|
+ struct lis302dl_platform_data *pdata = pdev->dev.platform_data;
|
|
|
|
lis = kzalloc(sizeof(*lis), GFP_KERNEL);
|
|
if (!lis)
|
|
@@ -548,38 +527,34 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
|
|
|
|
local_irq_save(flags);
|
|
|
|
- mutex_init(&lis->lock);
|
|
- lis->spi_dev = spi;
|
|
+ lis->dev = &pdev->dev;
|
|
|
|
- spi_set_drvdata(spi, lis);
|
|
+ dev_set_drvdata(lis->dev, lis);
|
|
|
|
- pdata = spi->dev.platform_data;
|
|
+ lis->pdata = pdata;
|
|
|
|
- rc = spi_setup(spi);
|
|
- if (rc < 0) {
|
|
- dev_err(&spi->dev, "error during spi_setup\n");
|
|
- dev_set_drvdata(&spi->dev, NULL);
|
|
- goto bail_free_lis;
|
|
- }
|
|
+ /* Configure our IO */
|
|
+ (lis->pdata->lis302dl_suspend_io)(lis, 1);
|
|
|
|
- wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
|
|
+ wai = (lis->pdata->lis302dl_bitbang_reg_read)(lis,
|
|
+ LIS302DL_REG_WHO_AM_I);
|
|
if (wai != LIS302DL_WHO_AM_I_MAGIC) {
|
|
- dev_err(&spi->dev, "unknown who_am_i signature 0x%02x\n", wai);
|
|
- dev_set_drvdata(&spi->dev, NULL);
|
|
+ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
|
|
+ dev_set_drvdata(lis->dev, NULL);
|
|
rc = -ENODEV;
|
|
goto bail_free_lis;
|
|
}
|
|
|
|
- rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
|
|
+ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
|
|
if (rc) {
|
|
- dev_err(&spi->dev, "error creating sysfs group\n");
|
|
+ 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(&spi->dev, "Unable to allocate input device\n");
|
|
+ dev_err(lis->dev, "Unable to allocate input device\n");
|
|
goto bail_sysfs;
|
|
}
|
|
|
|
@@ -601,57 +576,64 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
|
|
|
|
rc = input_register_device(lis->input_dev);
|
|
if (rc) {
|
|
- dev_err(&spi->dev, "error %d registering input device\n", rc);
|
|
+ dev_err(lis->dev, "error %d registering input device\n", rc);
|
|
goto bail_inp_dev;
|
|
}
|
|
|
|
if (__lis302dl_reset_device(lis))
|
|
- dev_err(&spi->dev, "device BOOT reload failed\n");
|
|
+ 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);
|
|
+ (lis->pdata->lis302dl_bitbang_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);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2, 0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL3,
|
|
+ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
|
|
+ LIS302DL_REG_FF_WU_THS_1, 0x0);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
|
|
+ LIS302DL_REG_FF_WU_DURATION_1, 0x00);
|
|
+ (lis->pdata->lis302dl_bitbang_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);
|
|
+ (lis->pdata->lis302dl_bitbang_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);
|
|
+ (lis->pdata->lis302dl_bitbang_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);
|
|
+ (lis->pdata->lis302dl_bitbang_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);
|
|
+ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
|
|
+ __lis302dl_int_mode(lis->dev, 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);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_STATUS);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_FF_WU_SRC_1);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_FF_WU_SRC_2);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CLICK_SRC);
|
|
|
|
- dev_info(&spi->dev, "Found %s\n", pdata->name);
|
|
+ dev_info(lis->dev, "Found %s\n", pdata->name);
|
|
|
|
lis->pdata = pdata;
|
|
|
|
- rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
|
|
+ rc = request_irq(pdata->interrupt, lis302dl_interrupt,
|
|
IRQF_TRIGGER_FALLING, "lis302dl", lis);
|
|
if (rc < 0) {
|
|
- dev_err(&spi->dev, "error requesting IRQ %d\n",
|
|
- lis->spi_dev->irq);
|
|
+ dev_err(lis->dev, "error requesting IRQ %d\n",
|
|
+ lis->pdata->interrupt);
|
|
goto bail_inp_reg;
|
|
}
|
|
local_irq_restore(flags);
|
|
@@ -662,50 +644,71 @@ bail_inp_reg:
|
|
bail_inp_dev:
|
|
input_free_device(lis->input_dev);
|
|
bail_sysfs:
|
|
- sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
|
|
+ sysfs_remove_group(&lis->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)
|
|
+static int __devexit lis302dl_remove(struct platform_device *pdev)
|
|
{
|
|
- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
|
+ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
|
|
unsigned long flags;
|
|
|
|
/* 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);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL3, 0x00);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2, 0x00);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL1, 0x00);
|
|
local_irq_restore(flags);
|
|
|
|
/* Cleanup resources */
|
|
- free_irq(lis->spi_dev->irq, lis);
|
|
- sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
|
|
+ free_irq(lis->pdata->interrupt, lis);
|
|
+ sysfs_remove_group(&pdev->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);
|
|
+ dev_set_drvdata(lis->dev, NULL);
|
|
kfree(lis);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
-static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
|
+
|
|
+static u8 regs_to_save[] = {
|
|
+ LIS302DL_REG_CTRL1,
|
|
+ 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,
|
|
+
|
|
+};
|
|
+
|
|
+static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
|
+ struct lis302dl_info *lis = dev_get_drvdata(&pdev->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_FF ||
|
|
lis->flags & LIS302DL_F_WUP_CLICK)
|
|
return 0;
|
|
|
|
- disable_irq(lis->spi_dev->irq);
|
|
+ disable_irq(lis->pdata->interrupt);
|
|
local_irq_save(flags);
|
|
|
|
/*
|
|
@@ -718,38 +721,15 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
|
(lis->pdata->lis302dl_suspend_io)(lis, 1);
|
|
|
|
/* save registers */
|
|
- lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
- lis->regs[LIS302DL_REG_CTRL2] = reg_read(lis, LIS302DL_REG_CTRL2);
|
|
- lis->regs[LIS302DL_REG_CTRL3] = reg_read(lis, LIS302DL_REG_CTRL3);
|
|
- lis->regs[LIS302DL_REG_FF_WU_CFG_1] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_CFG_1);
|
|
- lis->regs[LIS302DL_REG_FF_WU_THS_1] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_THS_1);
|
|
- lis->regs[LIS302DL_REG_FF_WU_DURATION_1] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_DURATION_1);
|
|
- lis->regs[LIS302DL_REG_FF_WU_CFG_2] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_CFG_2);
|
|
- lis->regs[LIS302DL_REG_FF_WU_THS_2] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_THS_2);
|
|
- lis->regs[LIS302DL_REG_FF_WU_DURATION_2] =
|
|
- reg_read(lis, LIS302DL_REG_FF_WU_DURATION_2);
|
|
- lis->regs[LIS302DL_REG_CLICK_CFG] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_CFG);
|
|
- lis->regs[LIS302DL_REG_CLICK_THSY_X] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_THSY_X);
|
|
- lis->regs[LIS302DL_REG_CLICK_THSZ] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_THSZ);
|
|
- lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_TIME_LIMIT);
|
|
- lis->regs[LIS302DL_REG_CLICK_LATENCY] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_LATENCY);
|
|
- lis->regs[LIS302DL_REG_CLICK_WINDOW] =
|
|
- reg_read(lis, LIS302DL_REG_CLICK_WINDOW);
|
|
+ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
|
|
+ lis->regs[regs_to_save[n]] =
|
|
+ (lis->pdata->lis302dl_bitbang_reg_read)(lis,
|
|
+ regs_to_save[n]);
|
|
|
|
/* power down */
|
|
- tmp = reg_read(lis, LIS302DL_REG_CTRL1);
|
|
+ tmp = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
|
|
tmp &= ~LIS302DL_CTRL1_PD;
|
|
- reg_write(lis, LIS302DL_REG_CTRL1, tmp);
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL1, tmp);
|
|
|
|
/* place our IO to the device in sleep-compatible states */
|
|
(lis->pdata->lis302dl_suspend_io)(lis, 0);
|
|
@@ -759,10 +739,11 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
|
return 0;
|
|
}
|
|
|
|
-static int lis302dl_resume(struct spi_device *spi)
|
|
+static int lis302dl_resume(struct platform_device *pdev)
|
|
{
|
|
- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
|
+ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
|
|
unsigned long flags;
|
|
+ int n;
|
|
|
|
if (lis->flags & LIS302DL_F_WUP_FF ||
|
|
lis->flags & LIS302DL_F_WUP_CLICK)
|
|
@@ -774,50 +755,28 @@ static int lis302dl_resume(struct spi_device *spi)
|
|
(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);
|
|
+ (lis->pdata->lis302dl_bitbang_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");
|
|
+ dev_err(&pdev->dev, "device BOOT reload failed\n");
|
|
|
|
- /* restore registers after resume */
|
|
- reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1] |
|
|
- LIS302DL_CTRL1_PD |
|
|
+ lis->regs[LIS302DL_REG_CTRL1] |= LIS302DL_CTRL1_PD |
|
|
LIS302DL_CTRL1_Xen |
|
|
LIS302DL_CTRL1_Yen |
|
|
- LIS302DL_CTRL1_Zen);
|
|
- reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
|
|
- reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
|
|
- lis->regs[LIS302DL_REG_FF_WU_CFG_1]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
|
|
- lis->regs[LIS302DL_REG_FF_WU_THS_1]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
|
|
- lis->regs[LIS302DL_REG_FF_WU_DURATION_1]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_CFG_2,
|
|
- lis->regs[LIS302DL_REG_FF_WU_CFG_2]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_THS_2,
|
|
- lis->regs[LIS302DL_REG_FF_WU_THS_2]);
|
|
- reg_write(lis, LIS302DL_REG_FF_WU_DURATION_2,
|
|
- lis->regs[LIS302DL_REG_FF_WU_DURATION_2]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_CFG,
|
|
- lis->regs[LIS302DL_REG_CLICK_CFG]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_THSY_X,
|
|
- lis->regs[LIS302DL_REG_CLICK_THSY_X]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_THSZ,
|
|
- lis->regs[LIS302DL_REG_CLICK_THSZ]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_TIME_LIMIT,
|
|
- lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_LATENCY,
|
|
- lis->regs[LIS302DL_REG_CLICK_LATENCY]);
|
|
- reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
|
|
- lis->regs[LIS302DL_REG_CLICK_WINDOW]);
|
|
+ LIS302DL_CTRL1_Zen;
|
|
+
|
|
+ /* restore registers after resume */
|
|
+ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
|
|
+ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
|
|
+ regs_to_save[n], lis->regs[regs_to_save[n]]);
|
|
|
|
local_irq_restore(flags);
|
|
- enable_irq(lis->spi_dev->irq);
|
|
+ enable_irq(lis->pdata->interrupt);
|
|
|
|
return 0;
|
|
}
|
|
@@ -826,7 +785,7 @@ static int lis302dl_resume(struct spi_device *spi)
|
|
#define lis302dl_resume NULL
|
|
#endif
|
|
|
|
-static struct spi_driver lis302dl_driver = {
|
|
+static struct platform_driver lis302dl_driver = {
|
|
.driver = {
|
|
.name = "lis302dl",
|
|
.owner = THIS_MODULE,
|
|
@@ -838,14 +797,14 @@ static struct spi_driver lis302dl_driver = {
|
|
.resume = lis302dl_resume,
|
|
};
|
|
|
|
-static int __init lis302dl_init(void)
|
|
+static int __devinit lis302dl_init(void)
|
|
{
|
|
- return spi_register_driver(&lis302dl_driver);
|
|
+ return platform_driver_register(&lis302dl_driver);
|
|
}
|
|
|
|
static void __exit lis302dl_exit(void)
|
|
{
|
|
- spi_unregister_driver(&lis302dl_driver);
|
|
+ platform_driver_unregister(&lis302dl_driver);
|
|
}
|
|
|
|
MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
|
|
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
|
|
index 7daa8b3..4578db4 100644
|
|
--- a/include/linux/lis302dl.h
|
|
+++ b/include/linux/lis302dl.h
|
|
@@ -15,15 +15,18 @@ struct lis302dl_platform_data {
|
|
unsigned long pin_mosi;
|
|
unsigned long pin_miso;
|
|
int open_drain;
|
|
- void (*lis302dl_bitbang_read)(struct lis302dl_info *);
|
|
+ int interrupt;
|
|
+ void (*lis302dl_bitbang_read_sample)(struct lis302dl_info *);
|
|
void (*lis302dl_suspend_io)(struct lis302dl_info *, int resuming);
|
|
+ int (*lis302dl_bitbang_reg_read)(struct lis302dl_info *, u8 reg);
|
|
+ void (*lis302dl_bitbang_reg_write)(struct lis302dl_info *, u8 reg,
|
|
+ u8 val);
|
|
};
|
|
|
|
struct lis302dl_info {
|
|
struct lis302dl_platform_data *pdata;
|
|
- struct spi_device *spi_dev;
|
|
+ struct device *dev;
|
|
struct input_dev *input_dev;
|
|
- struct mutex lock;
|
|
unsigned int flags;
|
|
u_int8_t regs[0x40];
|
|
};
|
|
--
|
|
1.5.6.5
|
|
|