mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-24 23:03:12 +02:00
1036 lines
29 KiB
Diff
1036 lines
29 KiB
Diff
|
From 0f43da072e28d0bad639cb6823a7759112ff3489 Mon Sep 17 00:00:00 2001
|
||
|
From: mokopatches <mokopatches@openmoko.org>
|
||
|
Date: Wed, 16 Jul 2008 14:46:56 +0100
|
||
|
Subject: [PATCH] gta02-acc.patch
|
||
|
|
||
|
---
|
||
|
arch/arm/mach-s3c2410/mach-gta01.c | 2 +-
|
||
|
arch/arm/mach-s3c2410/mach-qt2410.c | 2 +-
|
||
|
arch/arm/mach-s3c2440/mach-gta02.c | 181 +++++++++++++++--
|
||
|
drivers/input/misc/lis302dl.c | 350 ++++++++++++-------------------
|
||
|
drivers/spi/spi_s3c24xx_gpio.c | 23 ++-
|
||
|
include/asm-arm/arch-s3c2410/spi-gpio.h | 6 +-
|
||
|
include/linux/lis302dl.h | 102 +++++++++
|
||
|
7 files changed, 429 insertions(+), 237 deletions(-)
|
||
|
|
||
|
diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c
|
||
|
index 87bb189..0543daa 100644
|
||
|
--- a/arch/arm/mach-s3c2410/mach-gta01.c
|
||
|
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
|
||
|
@@ -510,7 +510,7 @@ static struct spi_board_info gta01_spi_board_info[] = {
|
||
|
},
|
||
|
};
|
||
|
|
||
|
-static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
|
||
|
+static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int csidx, int cs)
|
||
|
{
|
||
|
switch (cs) {
|
||
|
case BITBANG_CS_ACTIVE:
|
||
|
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
|
||
|
index a1caf4b..6f7b56d 100644
|
||
|
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
|
||
|
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
|
||
|
@@ -214,7 +214,7 @@ static struct platform_device qt2410_led = {
|
||
|
|
||
|
/* SPI */
|
||
|
|
||
|
-static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
|
||
|
+static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int csidx, int cs)
|
||
|
{
|
||
|
switch (cs) {
|
||
|
case BITBANG_CS_ACTIVE:
|
||
|
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
|
||
|
index d11da10..3fbb131 100644
|
||
|
--- a/arch/arm/mach-s3c2440/mach-gta02.c
|
||
|
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
|
||
|
@@ -78,6 +78,9 @@
|
||
|
|
||
|
#include <linux/glamofb.h>
|
||
|
|
||
|
+/* arbitrates which sensor IRQ owns the shared SPI bus */
|
||
|
+static spinlock_t motion_irq_lock;
|
||
|
+
|
||
|
static struct map_desc gta02_iodesc[] __initdata = {
|
||
|
{
|
||
|
.virtual = 0xe0000000,
|
||
|
@@ -377,8 +380,6 @@ static struct platform_device *gta02_devices[] __initdata = {
|
||
|
&s3c_device_usbgadget,
|
||
|
&s3c_device_nand,
|
||
|
&s3c_device_ts,
|
||
|
- &s3c_device_spi0,
|
||
|
- &s3c_device_spi1,
|
||
|
>a02_nor_flash,
|
||
|
};
|
||
|
|
||
|
@@ -478,10 +479,12 @@ static struct spi_board_info gta02_spi_board_info[] = {
|
||
|
},
|
||
|
};
|
||
|
|
||
|
+#if 0 /* currently this is not used and we use gpio spi */
|
||
|
static struct glamo_spi_info glamo_spi_cfg = {
|
||
|
.board_size = ARRAY_SIZE(gta02_spi_board_info),
|
||
|
.board_info = gta02_spi_board_info,
|
||
|
};
|
||
|
+#endif /* 0 */
|
||
|
|
||
|
static struct glamo_spigpio_info glamo_spigpio_cfg = {
|
||
|
.pin_clk = GLAMO_GPIO10_OUTPUT,
|
||
|
@@ -507,16 +510,99 @@ static struct platform_device gta01_led_dev = {
|
||
|
|
||
|
/* SPI: Accelerometers attached to SPI of s3c244x */
|
||
|
|
||
|
-static void gta02_spi_acc_set_cs(struct s3c2410_spi_info *spi, int cs, int pol)
|
||
|
+/*
|
||
|
+ * Situation is that Linux SPI can't work in an interrupt context, so we
|
||
|
+ * implement our own bitbang here. Arbitration is needed because not only
|
||
|
+ * can this interrupt happen at any time even if foreground wants to use
|
||
|
+ * the bitbang API from Linux, but multiple motion sensors can be on the
|
||
|
+ * same SPI bus, and multiple interrupts can happen.
|
||
|
+ *
|
||
|
+ * Foreground / interrupt arbitration is okay because the interrupts are
|
||
|
+ * disabled around all the foreground SPI code.
|
||
|
+ *
|
||
|
+ * Interrupt / Interrupt arbitration is evidently needed, otherwise we
|
||
|
+ * lose edge-triggered service after a while due to the two sensors sharing
|
||
|
+ * the SPI bus having irqs at the same time eventually.
|
||
|
+ *
|
||
|
+ * Servicing is typ 75 - 100us at 400MHz.
|
||
|
+ */
|
||
|
+
|
||
|
+/* #define DEBUG_SPEW_MS */
|
||
|
+#define MG_PER_SAMPLE 18
|
||
|
+
|
||
|
+void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
|
||
|
{
|
||
|
- s3c2410_gpio_setpin(cs, pol);
|
||
|
+ struct lis302dl_platform_data *pdata = lis->pdata;
|
||
|
+ u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
|
||
|
+ int n, n1;
|
||
|
+ unsigned long flags;
|
||
|
+#ifdef DEBUG_SPEW_MS
|
||
|
+ s8 x, y, z;
|
||
|
+#endif
|
||
|
+
|
||
|
+ spin_lock_irqsave(&motion_irq_lock, flags);
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
|
||
|
+ for (n = 0; n < 8; n++) { /* write the r/w, inc and address */
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_mosi, (shifter >> 7) & 1);
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
||
|
+ shifter <<= 1;
|
||
|
+ }
|
||
|
+ for (n = 0; n < 5; n++) { /* 5 consequetive registers */
|
||
|
+ for (n1 = 0; n1 < 8; n1++) { /* 8 bits each */
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
|
||
|
+ shifter <<= 1;
|
||
|
+ if (s3c2410_gpio_getpin(pdata->pin_miso))
|
||
|
+ shifter |= 1;
|
||
|
+ }
|
||
|
+ switch (n) {
|
||
|
+ case 0:
|
||
|
+#ifdef DEBUG_SPEW_MS
|
||
|
+ x = shifter;
|
||
|
+#endif
|
||
|
+ input_report_rel(lis->input_dev, REL_X, MG_PER_SAMPLE * (s8)shifter);
|
||
|
+ break;
|
||
|
+ case 2:
|
||
|
+#ifdef DEBUG_SPEW_MS
|
||
|
+ y = shifter;
|
||
|
+#endif
|
||
|
+ input_report_rel(lis->input_dev, REL_Y, MG_PER_SAMPLE * (s8)shifter);
|
||
|
+ break;
|
||
|
+ case 4:
|
||
|
+#ifdef DEBUG_SPEW_MS
|
||
|
+ z = shifter;
|
||
|
+#endif
|
||
|
+ input_report_rel(lis->input_dev, REL_Z, MG_PER_SAMPLE * (s8)shifter);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
|
||
|
+ spin_unlock_irqrestore(&motion_irq_lock, flags);
|
||
|
+ input_sync(lis->input_dev);
|
||
|
+#ifdef DEBUG_SPEW_MS
|
||
|
+ printk("%s: %d %d %d\n", pdata->name, x, y, z);
|
||
|
+#endif
|
||
|
}
|
||
|
|
||
|
-static const struct lis302dl_platform_data lis302_pdata[] = {
|
||
|
+
|
||
|
+struct lis302dl_platform_data lis302_pdata[] = {
|
||
|
{
|
||
|
- .name = "lis302-1 (top)"
|
||
|
+ .name = "lis302-1 (top)",
|
||
|
+ .pin_chip_select= S3C2410_GPD12,
|
||
|
+ .pin_clk = S3C2410_GPG7,
|
||
|
+ .pin_mosi = S3C2410_GPG6,
|
||
|
+ .pin_miso = S3C2410_GPG5,
|
||
|
+ .open_drain = 1, /* altered at runtime by PCB rev */
|
||
|
+ .lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
|
||
|
}, {
|
||
|
- .name = "lis302-2 (bottom)"
|
||
|
+ .name = "lis302-2 (bottom)",
|
||
|
+ .pin_chip_select= S3C2410_GPD13,
|
||
|
+ .pin_clk = S3C2410_GPG7,
|
||
|
+ .pin_mosi = S3C2410_GPG6,
|
||
|
+ .pin_miso = S3C2410_GPG5,
|
||
|
+ .open_drain = 1, /* altered at runtime by PCB rev */
|
||
|
+ .lis302dl_bitbang_read = gat02_lis302dl_bitbang_read,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
@@ -525,26 +611,75 @@ static struct spi_board_info gta02_spi_acc_bdinfo[] = {
|
||
|
.modalias = "lis302dl",
|
||
|
.platform_data = &lis302_pdata[0],
|
||
|
.irq = GTA02_IRQ_GSENSOR_1,
|
||
|
- .max_speed_hz = 400 * 1000,
|
||
|
+ .max_speed_hz = 10 * 1000 * 1000,
|
||
|
.bus_num = 1,
|
||
|
- .chip_select = S3C2410_GPD12,
|
||
|
+ .chip_select = 0,
|
||
|
.mode = SPI_MODE_3,
|
||
|
},
|
||
|
{
|
||
|
.modalias = "lis302dl",
|
||
|
.platform_data = &lis302_pdata[1],
|
||
|
.irq = GTA02_IRQ_GSENSOR_2,
|
||
|
- .max_speed_hz = 400 * 1000,
|
||
|
+ .max_speed_hz = 10 * 1000 * 1000,
|
||
|
.bus_num = 1,
|
||
|
- .chip_select = S3C2410_GPD13,
|
||
|
+ .chip_select = 1,
|
||
|
.mode = SPI_MODE_3,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
-static struct s3c2410_spi_info gta02_spi_acc_cfg = {
|
||
|
- .set_cs = gta02_spi_acc_set_cs,
|
||
|
+static void spi_acc_cs(struct s3c2410_spigpio_info *spigpio_info,
|
||
|
+ int csid, int cs)
|
||
|
+{
|
||
|
+ struct lis302dl_platform_data * plat_data =
|
||
|
+ (struct lis302dl_platform_data *)spigpio_info->
|
||
|
+ board_info->platform_data;
|
||
|
+ switch (cs) {
|
||
|
+ case BITBANG_CS_ACTIVE:
|
||
|
+ s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 0);
|
||
|
+ break;
|
||
|
+ case BITBANG_CS_INACTIVE:
|
||
|
+ s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 1);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static struct s3c2410_spigpio_info spi_gpio_cfg = {
|
||
|
+ .pin_clk = S3C2410_GPG7,
|
||
|
+ .pin_mosi = S3C2410_GPG6,
|
||
|
+ .pin_miso = S3C2410_GPG5,
|
||
|
.board_size = ARRAY_SIZE(gta02_spi_acc_bdinfo),
|
||
|
.board_info = gta02_spi_acc_bdinfo,
|
||
|
+ .chip_select = &spi_acc_cs,
|
||
|
+ .num_chipselect = 2,
|
||
|
+};
|
||
|
+
|
||
|
+static struct resource s3c_spi_acc_resource[] = {
|
||
|
+ [0] = {
|
||
|
+ .start = S3C2410_GPG3,
|
||
|
+ .end = S3C2410_GPG3,
|
||
|
+ },
|
||
|
+ [1] = {
|
||
|
+ .start = S3C2410_GPG5,
|
||
|
+ .end = S3C2410_GPG5,
|
||
|
+ },
|
||
|
+ [2] = {
|
||
|
+ .start = S3C2410_GPG6,
|
||
|
+ .end = S3C2410_GPG6,
|
||
|
+ },
|
||
|
+ [3] = {
|
||
|
+ .start = S3C2410_GPG7,
|
||
|
+ .end = S3C2410_GPG7,
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+static struct platform_device s3c_device_spi_acc = {
|
||
|
+ .name = "spi_s3c24xx_gpio",
|
||
|
+ .id = 1,
|
||
|
+ .num_resources = ARRAY_SIZE(s3c_spi_acc_resource),
|
||
|
+ .resource = s3c_spi_acc_resource,
|
||
|
+ .dev = {
|
||
|
+ .platform_data = &spi_gpio_cfg,
|
||
|
+ },
|
||
|
};
|
||
|
|
||
|
static struct resource gta02_led_resources[] = {
|
||
|
@@ -786,10 +921,21 @@ static void __init gta02_machine_init(void)
|
||
|
{
|
||
|
int rc;
|
||
|
|
||
|
+ switch (system_rev) {
|
||
|
+ case GTA02v6_SYSTEM_REV:
|
||
|
+ /* we need push-pull interrupt from motion sensors */
|
||
|
+ lis302_pdata[0].open_drain = 0;
|
||
|
+ lis302_pdata[1].open_drain = 0;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ spin_lock_init(&motion_irq_lock);
|
||
|
+
|
||
|
s3c_device_usb.dev.platform_data = >a02_usb_info;
|
||
|
s3c_device_nand.dev.platform_data = >a02_nand_info;
|
||
|
s3c_device_sdi.dev.platform_data = >a02_mmc_cfg;
|
||
|
- s3c_device_spi1.dev.platform_data = >a02_spi_acc_cfg;
|
||
|
|
||
|
/* Only GTA02v1 has a SD_DETECT GPIO. Since the slot is not
|
||
|
* hot-pluggable, this is not required anyway */
|
||
|
@@ -801,6 +947,12 @@ static void __init gta02_machine_init(void)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
+ /* acc sensor chip selects */
|
||
|
+ s3c2410_gpio_setpin(S3C2410_GPD12, 1);
|
||
|
+ s3c2410_gpio_cfgpin(S3C2410_GPD12, S3C2410_GPIO_OUTPUT);
|
||
|
+ s3c2410_gpio_setpin(S3C2410_GPD13, 1);
|
||
|
+ s3c2410_gpio_cfgpin(S3C2410_GPD13, S3C2410_GPIO_OUTPUT);
|
||
|
+
|
||
|
INIT_WORK(>a02_udc_vbus_drawer.work, __gta02_udc_vbus_draw);
|
||
|
s3c24xx_udc_set_platdata(>a02_udc_cfg);
|
||
|
set_s3c2410ts_info(>a02_ts_cfg);
|
||
|
@@ -829,6 +981,7 @@ static void __init gta02_machine_init(void)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
+ platform_device_register(&s3c_device_spi_acc);
|
||
|
platform_device_register(>a01_button_dev);
|
||
|
platform_device_register(>a01_pm_gsm_dev);
|
||
|
|
||
|
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
|
||
|
index 45c41c8..36bdcf7 100644
|
||
|
--- a/drivers/input/misc/lis302dl.c
|
||
|
+++ b/drivers/input/misc/lis302dl.c
|
||
|
@@ -33,117 +33,26 @@
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/delay.h>
|
||
|
-#include <linux/input.h>
|
||
|
#include <linux/irq.h>
|
||
|
#include <linux/interrupt.h>
|
||
|
#include <linux/sysfs.h>
|
||
|
|
||
|
#include <linux/lis302dl.h>
|
||
|
|
||
|
-#include <linux/spi/spi.h>
|
||
|
-
|
||
|
-#define LIS302DL_WHO_AM_I_MAGIC 0x3b
|
||
|
-
|
||
|
-enum lis302dl_reg {
|
||
|
- LIS302DL_REG_WHO_AM_I = 0x0f,
|
||
|
- LIS302DL_REG_CTRL1 = 0x20,
|
||
|
- LIS302DL_REG_CTRL2 = 0x21,
|
||
|
- LIS302DL_REG_CTRL3 = 0x22,
|
||
|
- LIS302DL_REG_HP_FILTER_RESET = 0x23,
|
||
|
- LIS302DL_REG_STATUS = 0x27,
|
||
|
- LIS302DL_REG_OUT_X = 0x29,
|
||
|
- LIS302DL_REG_OUT_Y = 0x2b,
|
||
|
- LIS302DL_REG_OUT_Z = 0x2d,
|
||
|
- LIS302DL_REG_FF_WU_CFG_1 = 0x30,
|
||
|
- LIS302DL_REG_FF_WU_SRC_1 = 0x31,
|
||
|
- LIS302DL_REG_FF_WU_THS_1 = 0x32,
|
||
|
- LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
|
||
|
- LIS302DL_REG_FF_WU_CFG_2 = 0x34,
|
||
|
- LIS302DL_REG_FF_WU_SRC_2 = 0x35,
|
||
|
- LIS302DL_REG_FF_WU_THS_2 = 0x36,
|
||
|
- LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
|
||
|
- LIS302DL_REG_CLICK_CFG = 0x38,
|
||
|
- LIS302DL_REG_CLICK_SRC = 0x39,
|
||
|
- LIS302DL_REG_CLICK_THSY_X = 0x3b,
|
||
|
- LIS302DL_REG_CLICK_THSZ = 0x3c,
|
||
|
- LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
|
||
|
- LIS302DL_REG_CLICK_LATENCY = 0x3e,
|
||
|
- LIS302DL_REG_CLICK_WINDOW = 0x3f,
|
||
|
-};
|
||
|
-
|
||
|
-enum lis302dl_reg_ctrl1 {
|
||
|
- LIS302DL_CTRL1_Xen = 0x01,
|
||
|
- LIS302DL_CTRL1_Yen = 0x02,
|
||
|
- LIS302DL_CTRL1_Zen = 0x04,
|
||
|
- LIS302DL_CTRL1_STM = 0x08,
|
||
|
- LIS302DL_CTRL1_STP = 0x10,
|
||
|
- LIS302DL_CTRL1_FS = 0x20,
|
||
|
- LIS302DL_CTRL1_PD = 0x40,
|
||
|
- LIS302DL_CTRL1_DR = 0x80,
|
||
|
-};
|
||
|
-
|
||
|
-enum lis302dl_reg_ctrl3 {
|
||
|
- LIS302DL_CTRL3_PP_OD = 0x40,
|
||
|
-};
|
||
|
-
|
||
|
-enum lis302dl_reg_status {
|
||
|
- LIS302DL_STATUS_XDA = 0x01,
|
||
|
- LIS302DL_STATUS_YDA = 0x02,
|
||
|
- LIS302DL_STATUS_ZDA = 0x04,
|
||
|
- LIS302DL_STATUS_XYZDA = 0x08,
|
||
|
- LIS302DL_STATUS_XOR = 0x10,
|
||
|
- LIS302DL_STATUS_YOR = 0x20,
|
||
|
- LIS302DL_STATUS_ZOR = 0x40,
|
||
|
- LIS302DL_STATUS_XYZOR = 0x80,
|
||
|
-};
|
||
|
-
|
||
|
-enum lis302dl_reg_ffwusrc1 {
|
||
|
- LIS302DL_FFWUSRC1_XL = 0x01,
|
||
|
- LIS302DL_FFWUSRC1_XH = 0x02,
|
||
|
- LIS302DL_FFWUSRC1_YL = 0x04,
|
||
|
- LIS302DL_FFWUSRC1_YH = 0x08,
|
||
|
- LIS302DL_FFWUSRC1_ZL = 0x10,
|
||
|
- LIS302DL_FFWUSRC1_ZH = 0x20,
|
||
|
- LIS302DL_FFWUSRC1_IA = 0x40,
|
||
|
-};
|
||
|
-
|
||
|
-enum lis302dl_reg_cloik_src {
|
||
|
- LIS302DL_CLICKSRC_SINGLE_X = 0x01,
|
||
|
- LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
|
||
|
- LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
|
||
|
- LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
|
||
|
- LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
|
||
|
- LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
|
||
|
- LIS302DL_CLICKSRC_IA = 0x40,
|
||
|
-};
|
||
|
-
|
||
|
-struct lis302dl_info {
|
||
|
- struct spi_device *spi_dev;
|
||
|
- struct input_dev *input_dev;
|
||
|
- struct mutex lock;
|
||
|
- struct work_struct work;
|
||
|
- unsigned int flags;
|
||
|
- unsigned int working;
|
||
|
- u_int8_t regs[0x40];
|
||
|
-};
|
||
|
-
|
||
|
-#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */
|
||
|
-#define LIS302DL_F_WUP_CLICK 0x0002
|
||
|
-#define LIS302DL_F_POWER 0x0010
|
||
|
-#define LIS302DL_F_FS 0x0020 /* ADC full scale */
|
||
|
-
|
||
|
/* lowlevel register access functions */
|
||
|
|
||
|
-#define READ_BIT 0x01
|
||
|
-#define MS_BIT 0x02
|
||
|
-#define ADDR_SHIFT 2
|
||
|
+#define READ_BIT 0x80
|
||
|
+#define READ_BIT_INC_ADS 0xc0
|
||
|
+#define ADDR_MASK 0x3f
|
||
|
|
||
|
-static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
|
||
|
+static u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
|
||
|
{
|
||
|
int rc;
|
||
|
u_int8_t cmd;
|
||
|
|
||
|
- cmd = (reg << ADDR_SHIFT) | READ_BIT;
|
||
|
+ BUG_ON(reg & ~ADDR_MASK);
|
||
|
+
|
||
|
+ cmd = reg | READ_BIT;
|
||
|
|
||
|
rc = spi_w8r8(lis->spi_dev, cmd);
|
||
|
|
||
|
@@ -161,11 +70,13 @@ static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
|
||
|
+static int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
|
||
|
{
|
||
|
u_int8_t buf[2];
|
||
|
|
||
|
- buf[0] = (reg << ADDR_SHIFT);
|
||
|
+ BUG_ON(reg & ~ADDR_MASK);
|
||
|
+
|
||
|
+ buf[0] = reg;
|
||
|
buf[1] = val;
|
||
|
|
||
|
return spi_write(lis->spi_dev, buf, sizeof(buf));
|
||
|
@@ -207,10 +118,10 @@ static int reg_set_bit_mask(struct lis302dl_info *lis,
|
||
|
enum lis302dl_intmode {
|
||
|
LIS302DL_INTMODE_GND = 0x00,
|
||
|
LIS302DL_INTMODE_FF_WU_1 = 0x01,
|
||
|
- LIX302DL_INTMODE_FF_WU_2 = 0x02,
|
||
|
- LIX302DL_INTMODE_FF_WU_12 = 0x03,
|
||
|
- LIX302DL_INTMODE_DATA_READY = 0x04,
|
||
|
- LIX302DL_INTMODE_CLICK = 0x07,
|
||
|
+ LIS302DL_INTMODE_FF_WU_2 = 0x02,
|
||
|
+ LIS302DL_INTMODE_FF_WU_12 = 0x03,
|
||
|
+ LIS302DL_INTMODE_DATA_READY = 0x04,
|
||
|
+ LIS302DL_INTMODE_CLICK = 0x07,
|
||
|
};
|
||
|
|
||
|
static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
|
||
|
@@ -218,12 +129,18 @@ static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
|
||
|
{
|
||
|
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||
|
|
||
|
- if (int_pin == 1)
|
||
|
+ switch (int_pin) {
|
||
|
+ case 1:
|
||
|
reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
|
||
|
- else if (int_pin == 2)
|
||
|
+ break;
|
||
|
+ case 2:
|
||
|
reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ BUG();
|
||
|
+ }
|
||
|
}
|
||
|
-
|
||
|
+#if 0
|
||
|
static void _report_btn_single(struct input_dev *inp, int btn)
|
||
|
{
|
||
|
input_report_key(inp, btn, 1);
|
||
|
@@ -241,95 +158,14 @@ static void _report_btn_double(struct input_dev *inp, int btn)
|
||
|
input_sync(inp);
|
||
|
input_report_key(inp, btn, 0);
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
-static void lis302dl_work(struct work_struct *work)
|
||
|
-{
|
||
|
- struct lis302dl_info *lis =
|
||
|
- container_of(work, struct lis302dl_info, work);
|
||
|
-
|
||
|
- u_int8_t status, ff_wu_src_1, click_src;
|
||
|
- u_int8_t val;
|
||
|
-
|
||
|
- lis->working = 1;
|
||
|
-
|
||
|
- status = reg_read(lis, LIS302DL_REG_STATUS);
|
||
|
- ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
|
||
|
- click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
|
||
|
-
|
||
|
- if (status & LIS302DL_STATUS_XDA) {
|
||
|
- val = reg_read(lis, LIS302DL_REG_OUT_X);
|
||
|
- if (lis->flags & LIS302DL_F_FS)
|
||
|
- val = val << 2;
|
||
|
- input_report_rel(lis->input_dev, REL_X, val);
|
||
|
- }
|
||
|
-
|
||
|
- if (status & LIS302DL_STATUS_YDA) {
|
||
|
- val = reg_read(lis, LIS302DL_REG_OUT_Y);
|
||
|
- if (lis->flags & LIS302DL_F_FS)
|
||
|
- val = val << 2;
|
||
|
- input_report_rel(lis->input_dev, REL_Y, val);
|
||
|
- }
|
||
|
-
|
||
|
- if (status & LIS302DL_STATUS_ZDA) {
|
||
|
- val = reg_read(lis, LIS302DL_REG_OUT_Z);
|
||
|
- if (lis->flags & LIS302DL_F_FS)
|
||
|
- val = val << 2;
|
||
|
- input_report_rel(lis->input_dev, REL_Z, val);
|
||
|
- }
|
||
|
-
|
||
|
- if (status & 0xf0)
|
||
|
- dev_dbg(&lis->spi_dev->dev, "overrun!\n");
|
||
|
-
|
||
|
- /* FIXME: implement overrun statistics */
|
||
|
-
|
||
|
- if (ff_wu_src_1 & LIS302DL_FFWUSRC1_IA) {
|
||
|
- /* FIXME: free fall interrupt handling */
|
||
|
- }
|
||
|
-
|
||
|
- if (click_src & LIS302DL_CLICKSRC_IA) {
|
||
|
- if (click_src & LIS302DL_CLICKSRC_SINGLE_X)
|
||
|
- _report_btn_single(lis->input_dev, BTN_X);
|
||
|
- if (click_src & LIS302DL_CLICKSRC_DOUBLE_X)
|
||
|
- _report_btn_double(lis->input_dev, BTN_X);
|
||
|
-
|
||
|
- if (click_src & LIS302DL_CLICKSRC_SINGLE_Y)
|
||
|
- _report_btn_single(lis->input_dev, BTN_Y);
|
||
|
- if (click_src & LIS302DL_CLICKSRC_DOUBLE_Y)
|
||
|
- _report_btn_double(lis->input_dev, BTN_Y);
|
||
|
-
|
||
|
- if (click_src & LIS302DL_CLICKSRC_SINGLE_Z)
|
||
|
- _report_btn_single(lis->input_dev, BTN_Z);
|
||
|
- if (click_src & LIS302DL_CLICKSRC_DOUBLE_Z)
|
||
|
- _report_btn_double(lis->input_dev, BTN_Z);
|
||
|
- }
|
||
|
-
|
||
|
- lis->working = 0;
|
||
|
- input_sync(lis->input_dev);
|
||
|
- put_device(&lis->spi_dev->dev);
|
||
|
-
|
||
|
- enable_irq(lis->spi_dev->irq);
|
||
|
-}
|
||
|
-
|
||
|
-static void lis302dl_schedule_work(struct lis302dl_info *lis)
|
||
|
-{
|
||
|
- int status;
|
||
|
-
|
||
|
- get_device(&lis->spi_dev->dev);
|
||
|
- status = schedule_work(&lis->work);
|
||
|
- if (!status && !lis->working)
|
||
|
- dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
|
||
|
-}
|
||
|
|
||
|
static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
|
||
|
{
|
||
|
struct lis302dl_info *lis = _lis;
|
||
|
|
||
|
- lis302dl_schedule_work(lis);
|
||
|
-
|
||
|
- /* Disable any further interrupts until we have processed
|
||
|
- * the current one */
|
||
|
- disable_irq(lis->spi_dev->irq);
|
||
|
-
|
||
|
+ (lis->pdata->lis302dl_bitbang_read)(lis);
|
||
|
return IRQ_HANDLED;
|
||
|
}
|
||
|
|
||
|
@@ -388,6 +224,7 @@ static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
|
||
|
static struct attribute *lis302dl_sysfs_entries[] = {
|
||
|
&dev_attr_sample_rate.attr,
|
||
|
&dev_attr_full_scale.attr,
|
||
|
+ NULL
|
||
|
};
|
||
|
|
||
|
static struct attribute_group lis302dl_attr_group = {
|
||
|
@@ -402,9 +239,16 @@ static int lis302dl_input_open(struct input_dev *inp)
|
||
|
struct lis302dl_info *lis = inp->private;
|
||
|
u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
|
||
|
LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
+ local_save_flags(flags);
|
||
|
/* make sure we're powered up and generate data ready */
|
||
|
reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
|
||
|
+ local_irq_restore(flags);
|
||
|
+
|
||
|
+ /* kick it off -- since we are edge triggered, if we missed the edge
|
||
|
+ * permanent low interrupt is death for us */
|
||
|
+ (lis->pdata->lis302dl_bitbang_read)(lis);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -414,9 +258,12 @@ static void lis302dl_input_close(struct input_dev *inp)
|
||
|
struct lis302dl_info *lis = inp->private;
|
||
|
u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
|
||
|
LIS302DL_CTRL1_Zen;
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ local_save_flags(flags);
|
||
|
|
||
|
/* since the input core already serializes access and makes sure we
|
||
|
- * only see close() for the close of the lastre user, we can safely
|
||
|
+ * only see close() for the close of the last user, we can safely
|
||
|
* disable the data ready events */
|
||
|
reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
|
||
|
|
||
|
@@ -426,6 +273,7 @@ static void lis302dl_input_close(struct input_dev *inp)
|
||
|
reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
|
||
|
0x00);
|
||
|
}
|
||
|
+ local_irq_restore(flags);
|
||
|
}
|
||
|
|
||
|
static int __devinit lis302dl_probe(struct spi_device *spi)
|
||
|
@@ -433,84 +281,138 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
|
||
|
int rc;
|
||
|
struct lis302dl_info *lis;
|
||
|
u_int8_t wai;
|
||
|
+ unsigned long flags;
|
||
|
+ struct lis302dl_platform_data *pdata;
|
||
|
|
||
|
lis = kzalloc(sizeof(*lis), GFP_KERNEL);
|
||
|
if (!lis)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
+ local_save_flags(flags);
|
||
|
+
|
||
|
mutex_init(&lis->lock);
|
||
|
- INIT_WORK(&lis->work, lis302dl_work);
|
||
|
lis->spi_dev = spi;
|
||
|
|
||
|
spi_set_drvdata(spi, lis);
|
||
|
|
||
|
+ pdata = spi->dev.platform_data;
|
||
|
+
|
||
|
rc = spi_setup(spi);
|
||
|
if (rc < 0) {
|
||
|
- printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
|
||
|
+ dev_err(&spi->dev, "error during spi_setup\n");
|
||
|
dev_set_drvdata(&spi->dev, NULL);
|
||
|
- kfree(lis);
|
||
|
- return rc;
|
||
|
+ goto bail_free_lis;
|
||
|
}
|
||
|
|
||
|
wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
|
||
|
if (wai != LIS302DL_WHO_AM_I_MAGIC) {
|
||
|
- printk(KERN_ERR "unknown who_am_i signature 0x%02x\n", wai);
|
||
|
+ dev_err(&spi->dev, "unknown who_am_i signature 0x%02x\n", wai);
|
||
|
dev_set_drvdata(&spi->dev, NULL);
|
||
|
- kfree(lis);
|
||
|
- return -ENODEV;
|
||
|
- }
|
||
|
-
|
||
|
- /* switch interrupt to open collector */
|
||
|
- reg_write(lis, LIS302DL_CTRL3_PP_OD, 0x7c);
|
||
|
-
|
||
|
- rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt, IRQF_DISABLED,
|
||
|
- "lis302dl", NULL);
|
||
|
- if (rc < 0) {
|
||
|
- dev_err(&spi->dev, "error requesting IRQ %d\n",
|
||
|
- lis->spi_dev->irq);
|
||
|
- /* FIXME */
|
||
|
- return rc;
|
||
|
+ rc = -ENODEV;
|
||
|
+ goto bail_free_lis;
|
||
|
}
|
||
|
|
||
|
rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
|
||
|
if (rc) {
|
||
|
dev_err(&spi->dev, "error creating sysfs group\n");
|
||
|
- /* FIXME */
|
||
|
- return rc;
|
||
|
+ goto bail_free_lis;
|
||
|
}
|
||
|
|
||
|
/* initialize input layer details */
|
||
|
lis->input_dev = input_allocate_device();
|
||
|
if (!lis->input_dev) {
|
||
|
dev_err(&spi->dev, "Unable to allocate input device\n");
|
||
|
- /* FIXME */
|
||
|
+ goto bail_sysfs;
|
||
|
}
|
||
|
|
||
|
set_bit(EV_REL, lis->input_dev->evbit);
|
||
|
- set_bit(EV_KEY, lis->input_dev->evbit);
|
||
|
+ set_bit(REL_X, lis->input_dev->relbit);
|
||
|
+ set_bit(REL_Y, lis->input_dev->relbit);
|
||
|
+ set_bit(REL_Z, lis->input_dev->relbit);
|
||
|
+/* set_bit(EV_KEY, lis->input_dev->evbit);
|
||
|
set_bit(BTN_X, lis->input_dev->keybit);
|
||
|
set_bit(BTN_Y, lis->input_dev->keybit);
|
||
|
set_bit(BTN_Z, lis->input_dev->keybit);
|
||
|
-
|
||
|
+*/
|
||
|
lis->input_dev->private = lis;
|
||
|
- lis->input_dev->name = "lis302dl"; /* FIXME: platform data */
|
||
|
- lis->input_dev->id.bustype = BUS_I2C; /* FIXME: SPI Bus */
|
||
|
+ lis->input_dev->name = pdata->name;
|
||
|
+ /* SPI Bus not defined as a valid bus for input subsystem*/
|
||
|
+ lis->input_dev->id.bustype = BUS_I2C; /* lie about it */
|
||
|
lis->input_dev->open = lis302dl_input_open;
|
||
|
lis->input_dev->close = lis302dl_input_close;
|
||
|
|
||
|
- input_register_device(lis->input_dev);
|
||
|
+ rc = input_register_device(lis->input_dev);
|
||
|
+ if (rc) {
|
||
|
+ dev_err(&spi->dev, "error %d registering input device\n", rc);
|
||
|
+ goto bail_inp_dev;
|
||
|
+ }
|
||
|
+
|
||
|
+ reg_write(lis, LIS302DL_REG_CTRL1, 0x47);
|
||
|
+ reg_write(lis, LIS302DL_REG_CTRL3, 0xc0);
|
||
|
+ reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x14);
|
||
|
+ reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
|
||
|
+ reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x95);
|
||
|
+
|
||
|
+ reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
|
||
|
+ LIS302DL_CTRL1_Yen |
|
||
|
+ LIS302DL_CTRL1_Zen);
|
||
|
+
|
||
|
+ if (pdata->open_drain)
|
||
|
+ /* switch interrupt to open collector, active-low */
|
||
|
+ reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
|
||
|
+ LIS302DL_CTRL3_IHL);
|
||
|
+ else
|
||
|
+ /* push-pull, active-low */
|
||
|
+ reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
|
||
|
+
|
||
|
+ lis302dl_int_mode(spi, 1, LIS302DL_INTMODE_DATA_READY);
|
||
|
+ lis302dl_int_mode(spi, 2, LIS302DL_INTMODE_DATA_READY);
|
||
|
+
|
||
|
+ reg_read(lis, LIS302DL_REG_STATUS);
|
||
|
+ reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
|
||
|
+ reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
|
||
|
+ reg_read(lis, LIS302DL_REG_CLICK_SRC);
|
||
|
|
||
|
+ dev_info(&spi->dev, "Found %s\n", pdata->name);
|
||
|
+
|
||
|
+ lis->pdata = pdata;
|
||
|
+
|
||
|
+ rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
|
||
|
+ IRQF_TRIGGER_FALLING, "lis302dl", lis);
|
||
|
+ if (rc < 0) {
|
||
|
+ dev_err(&spi->dev, "error requesting IRQ %d\n",
|
||
|
+ lis->spi_dev->irq);
|
||
|
+ goto bail_inp_reg;
|
||
|
+ }
|
||
|
+ local_irq_restore(flags);
|
||
|
return 0;
|
||
|
+
|
||
|
+bail_inp_reg:
|
||
|
+ input_unregister_device(lis->input_dev);
|
||
|
+bail_inp_dev:
|
||
|
+ input_free_device(lis->input_dev);
|
||
|
+bail_sysfs:
|
||
|
+ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
|
||
|
+bail_free_lis:
|
||
|
+ kfree(lis);
|
||
|
+ local_irq_restore(flags);
|
||
|
+ return rc;
|
||
|
}
|
||
|
|
||
|
static int __devexit lis302dl_remove(struct spi_device *spi)
|
||
|
{
|
||
|
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
/* power down the device */
|
||
|
+ local_save_flags(flags);
|
||
|
reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
|
||
|
+ local_irq_restore(flags);
|
||
|
+
|
||
|
sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
|
||
|
input_unregister_device(lis->input_dev);
|
||
|
+ if (lis->input_dev)
|
||
|
+ input_free_device(lis->input_dev);
|
||
|
dev_set_drvdata(&spi->dev, NULL);
|
||
|
kfree(lis);
|
||
|
|
||
|
@@ -521,6 +423,10 @@ static int __devexit lis302dl_remove(struct spi_device *spi)
|
||
|
static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
||
|
{
|
||
|
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ disable_irq(lis->spi_dev->irq);
|
||
|
+ local_save_flags(flags);
|
||
|
|
||
|
/* save registers */
|
||
|
lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
|
||
|
@@ -561,12 +467,17 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
|
||
|
reg_write(lis, LIS302DL_REG_CTRL1, tmp);
|
||
|
}
|
||
|
|
||
|
+ local_irq_restore(flags);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int lis302dl_resume(struct spi_device *spi)
|
||
|
{
|
||
|
struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ local_save_flags(flags);
|
||
|
|
||
|
/* restore registers after resume */
|
||
|
reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
|
||
|
@@ -597,6 +508,9 @@ static int lis302dl_resume(struct spi_device *spi)
|
||
|
reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
|
||
|
lis->regs[LIS302DL_REG_CLICK_WINDOW]);
|
||
|
|
||
|
+ local_irq_restore(flags);
|
||
|
+ enable_irq(lis->spi_dev->irq);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
#else
|
||
|
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
|
||
|
index e33f614..ccadf35 100644
|
||
|
--- a/drivers/spi/spi_s3c24xx_gpio.c
|
||
|
+++ b/drivers/spi/spi_s3c24xx_gpio.c
|
||
|
@@ -91,7 +91,7 @@ static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
|
||
|
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
|
||
|
|
||
|
if (sg->info && sg->info->chip_select)
|
||
|
- (sg->info->chip_select)(sg->info, value);
|
||
|
+ (sg->info->chip_select)(sg->info, dev->chip_select, value);
|
||
|
}
|
||
|
|
||
|
static int s3c2410_spigpio_probe(struct platform_device *dev)
|
||
|
@@ -100,6 +100,7 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
|
||
|
struct spi_master *master;
|
||
|
struct s3c2410_spigpio *sp;
|
||
|
int ret;
|
||
|
+ int i;
|
||
|
|
||
|
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
|
||
|
if (master == NULL) {
|
||
|
@@ -112,9 +113,11 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
|
||
|
|
||
|
platform_set_drvdata(dev, sp);
|
||
|
|
||
|
- /* copy in the plkatform data */
|
||
|
+ /* copy in the platform data */
|
||
|
info = sp->info = dev->dev.platform_data;
|
||
|
|
||
|
+ master->num_chipselect = info->num_chipselect;
|
||
|
+
|
||
|
/* setup spi bitbang adaptor */
|
||
|
sp->bitbang.master = spi_master_get(master);
|
||
|
sp->bitbang.master->bus_num = info->bus_num;
|
||
|
@@ -142,6 +145,22 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
|
||
|
if (ret)
|
||
|
goto err_no_bitbang;
|
||
|
|
||
|
+ /* register the chips to go with the board */
|
||
|
+
|
||
|
+ for (i = 0; i < sp->info->board_size; i++) {
|
||
|
+ struct spi_device *spidev;
|
||
|
+
|
||
|
+ dev_info(&dev->dev, "registering %p: %s\n",
|
||
|
+ &sp->info->board_info[i],
|
||
|
+ sp->info->board_info[i].modalias);
|
||
|
+
|
||
|
+ sp->info->board_info[i].controller_data = sp;
|
||
|
+ spidev = spi_new_device(master, sp->info->board_info + i);
|
||
|
+ if (spidev)
|
||
|
+ spidev->max_speed_hz =
|
||
|
+ sp->info->board_info[i].max_speed_hz;
|
||
|
+ }
|
||
|
+
|
||
|
return 0;
|
||
|
|
||
|
err_no_bitbang:
|
||
|
diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h
|
||
|
index 7380373..d4efc97 100644
|
||
|
--- a/include/asm-arm/arch-s3c2410/spi-gpio.h
|
||
|
+++ b/include/asm-arm/arch-s3c2410/spi-gpio.h
|
||
|
@@ -19,8 +19,12 @@ struct s3c2410_spigpio_info {
|
||
|
unsigned long pin_miso;
|
||
|
|
||
|
int bus_num;
|
||
|
+ int num_chipselect;
|
||
|
|
||
|
- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
|
||
|
+ unsigned long board_size;
|
||
|
+ struct spi_board_info *board_info;
|
||
|
+
|
||
|
+ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs);
|
||
|
};
|
||
|
|
||
|
|
||
|
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
|
||
|
index d0f31be..2dea813 100644
|
||
|
--- a/include/linux/lis302dl.h
|
||
|
+++ b/include/linux/lis302dl.h
|
||
|
@@ -2,10 +2,112 @@
|
||
|
#define _LINUX_LIS302DL_H
|
||
|
|
||
|
#include <linux/types.h>
|
||
|
+#include <linux/spi/spi.h>
|
||
|
+#include <linux/input.h>
|
||
|
+
|
||
|
+
|
||
|
+struct lis302dl_info;
|
||
|
|
||
|
struct lis302dl_platform_data {
|
||
|
char *name;
|
||
|
+ unsigned long pin_chip_select;
|
||
|
+ unsigned long pin_clk;
|
||
|
+ unsigned long pin_mosi;
|
||
|
+ unsigned long pin_miso;
|
||
|
+ int open_drain;
|
||
|
+ void (*lis302dl_bitbang_read)(struct lis302dl_info *);
|
||
|
+};
|
||
|
+
|
||
|
+struct lis302dl_info {
|
||
|
+ struct lis302dl_platform_data *pdata;
|
||
|
+ struct spi_device *spi_dev;
|
||
|
+ struct input_dev *input_dev;
|
||
|
+ struct mutex lock;
|
||
|
+ unsigned int flags;
|
||
|
+ u_int8_t regs[0x40];
|
||
|
+};
|
||
|
+
|
||
|
+enum lis302dl_reg {
|
||
|
+ LIS302DL_REG_WHO_AM_I = 0x0f,
|
||
|
+ LIS302DL_REG_CTRL1 = 0x20,
|
||
|
+ LIS302DL_REG_CTRL2 = 0x21,
|
||
|
+ LIS302DL_REG_CTRL3 = 0x22,
|
||
|
+ LIS302DL_REG_HP_FILTER_RESET = 0x23,
|
||
|
+ LIS302DL_REG_STATUS = 0x27,
|
||
|
+ LIS302DL_REG_OUT_X = 0x29,
|
||
|
+ LIS302DL_REG_OUT_Y = 0x2b,
|
||
|
+ LIS302DL_REG_OUT_Z = 0x2d,
|
||
|
+ LIS302DL_REG_FF_WU_CFG_1 = 0x30,
|
||
|
+ LIS302DL_REG_FF_WU_SRC_1 = 0x31,
|
||
|
+ LIS302DL_REG_FF_WU_THS_1 = 0x32,
|
||
|
+ LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
|
||
|
+ LIS302DL_REG_FF_WU_CFG_2 = 0x34,
|
||
|
+ LIS302DL_REG_FF_WU_SRC_2 = 0x35,
|
||
|
+ LIS302DL_REG_FF_WU_THS_2 = 0x36,
|
||
|
+ LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
|
||
|
+ LIS302DL_REG_CLICK_CFG = 0x38,
|
||
|
+ LIS302DL_REG_CLICK_SRC = 0x39,
|
||
|
+ LIS302DL_REG_CLICK_THSY_X = 0x3b,
|
||
|
+ LIS302DL_REG_CLICK_THSZ = 0x3c,
|
||
|
+ LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
|
||
|
+ LIS302DL_REG_CLICK_LATENCY = 0x3e,
|
||
|
+ LIS302DL_REG_CLICK_WINDOW = 0x3f,
|
||
|
+};
|
||
|
+
|
||
|
+enum lis302dl_reg_ctrl1 {
|
||
|
+ LIS302DL_CTRL1_Xen = 0x01,
|
||
|
+ LIS302DL_CTRL1_Yen = 0x02,
|
||
|
+ LIS302DL_CTRL1_Zen = 0x04,
|
||
|
+ LIS302DL_CTRL1_STM = 0x08,
|
||
|
+ LIS302DL_CTRL1_STP = 0x10,
|
||
|
+ LIS302DL_CTRL1_FS = 0x20,
|
||
|
+ LIS302DL_CTRL1_PD = 0x40,
|
||
|
+ LIS302DL_CTRL1_DR = 0x80,
|
||
|
+};
|
||
|
+
|
||
|
+enum lis302dl_reg_ctrl3 {
|
||
|
+ LIS302DL_CTRL3_PP_OD = 0x40,
|
||
|
+ LIS302DL_CTRL3_IHL = 0x80,
|
||
|
};
|
||
|
|
||
|
+enum lis302dl_reg_status {
|
||
|
+ LIS302DL_STATUS_XDA = 0x01,
|
||
|
+ LIS302DL_STATUS_YDA = 0x02,
|
||
|
+ LIS302DL_STATUS_ZDA = 0x04,
|
||
|
+ LIS302DL_STATUS_XYZDA = 0x08,
|
||
|
+ LIS302DL_STATUS_XOR = 0x10,
|
||
|
+ LIS302DL_STATUS_YOR = 0x20,
|
||
|
+ LIS302DL_STATUS_ZOR = 0x40,
|
||
|
+ LIS302DL_STATUS_XYZOR = 0x80,
|
||
|
+};
|
||
|
+
|
||
|
+enum lis302dl_reg_ffwusrc1 {
|
||
|
+ LIS302DL_FFWUSRC1_XL = 0x01,
|
||
|
+ LIS302DL_FFWUSRC1_XH = 0x02,
|
||
|
+ LIS302DL_FFWUSRC1_YL = 0x04,
|
||
|
+ LIS302DL_FFWUSRC1_YH = 0x08,
|
||
|
+ LIS302DL_FFWUSRC1_ZL = 0x10,
|
||
|
+ LIS302DL_FFWUSRC1_ZH = 0x20,
|
||
|
+ LIS302DL_FFWUSRC1_IA = 0x40,
|
||
|
+};
|
||
|
+
|
||
|
+enum lis302dl_reg_cloik_src {
|
||
|
+ LIS302DL_CLICKSRC_SINGLE_X = 0x01,
|
||
|
+ LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
|
||
|
+ LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
|
||
|
+ LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
|
||
|
+ LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
|
||
|
+ LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
|
||
|
+ LIS302DL_CLICKSRC_IA = 0x40,
|
||
|
+};
|
||
|
+
|
||
|
+#define LIS302DL_WHO_AM_I_MAGIC 0x3b
|
||
|
+
|
||
|
+#define LIS302DL_F_WUP_FF 0x0001 /* wake up from free fall */
|
||
|
+#define LIS302DL_F_WUP_CLICK 0x0002
|
||
|
+#define LIS302DL_F_POWER 0x0010
|
||
|
+#define LIS302DL_F_FS 0x0020 /* ADC full scale */
|
||
|
+
|
||
|
+
|
||
|
#endif /* _LINUX_LIS302DL_H */
|
||
|
|
||
|
--
|
||
|
1.5.6.3
|
||
|
|