aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:11:12 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:11:12 +0000
commit53df9cfb700f5bdb144f232cc0ef02785aa5744f (patch)
treed069d38f32e8ce5ff966072b2bd13c0adb2453a6 /arch
parent2ea904b26ed24ece7ea09d61967fe44c1d6cc2a4 (diff)
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. Not working in interrupt context made trouble using interrupt lockout as locking [21474615.495000] BUG: sleeping function called from invalid context at kernel/sched.c:4684 [21474615.495000] in_atomic():0, irqs_disabled():128 [21474615.495000] 2 locks held by bash/779: [21474615.495000] #0: (&buffer->mutex){....}, at: [<c00ec1b0>] sysfs_write_file+0x30/0x80 [21474615.495000] #1: (pm_mutex){....}, at: [<c007a34c>] enter_state+0xd4/0x10c [21474615.495000] [<c0032a14>] (dump_stack+0x0/0x14) from [<c0049410>] (__might_sleep+0xdc/0xf8) [21474615.495000] [<c0049334>] (__might_sleep+0x0/0xf8) from [<c0316c38>] (wait_for_common+0x28/0x190) [21474615.495000] r5:c79ffd00 r4:c79ffd4c [21474615.495000] [<c0316c10>] (wait_for_common+0x0/0x190) from [<c0316e30>] (wait_for_completion+0x18/0x1c) [21474615.495000] r8:c79ffd84 r7:c79c4800 r6:c79ffd00 r5:c79ffd20 r4:c79ffd4c [21474615.495000] [<c0316e18>] (wait_for_completion+0x0/0x1c) from [<c01d28ec>] (spi_sync+0xa0/0xb8) [21474615.495000] [<c01d284c>] (spi_sync+0x0/0xb8) from [<c020ca10>] (__reg_write+0x88/0x94) [21474615.495000] [<c020c988>] (__reg_write+0x0/0x94) from [<c020cc30>] (lis302dl_resume+0x54/0x198) [21474615.495000] r6:60000013 r5:c79c4800 r4:c79bc9c0 [21474615.495000] [<c020cbdc>] (lis302dl_resume+0x0/0x198) from [<c01d2fb0>] (spi_resume+0x38/0x44) [21474615.495000] r6:00000010 r5:c79c4800 r4:c79c4974 [21474615.495000] [<c01d2f78>] (spi_resume+0x0/0x44) from [<c0198f34>] (resume_device+0x8c/0x1b0) [21474615.495000] [<c0198ea8>] (resume_device+0x0/0x1b0) from [<c01990c0>] (dpm_resume+0x68/0x134) [21474615.495000] r7:00000003 r6:00000010 r5:c79c4800 r4:c79c4974 [21474615.495000] [<c0199058>] (dpm_resume+0x0/0x134) from [<c01991b4>] (device_resume+0x28/0x38) [21474615.495000] r6:00000003 r5:c08b7188 r4:00000010 [21474615.495000] [<c019918c>] (device_resume+0x0/0x38) from [<c007a0f8>] (suspend_devices_and_enter+0x110/0x180) [21474615.495000] r4:00000000 [21474615.495000] [<c0079fe8>] (suspend_devices_and_enter+0x0/0x180) from [<c007a320>] (enter_state+0xa8/0x10c) [21474615.495000] r6:00000003 r5:c03aa414 r4:00000000 [21474615.495000] [<c007a278>] (enter_state+0x0/0x10c) from [<c007a430>] (state_store+0xac/0xc0) [21474615.495000] r6:c7b80000 r5:00000003 r4:c03aa414 [21474615.495000] [<c007a384>] (state_store+0x0/0xc0) from [<c014dfb4>] (kobj_attr_store+0x24/0x30) [21474615.495000] [<c014df90>] (kobj_attr_store+0x0/0x30) from [<c00ebe58>] (flush_write_buffer+0x54/0x68) [21474615.495000] [<c00ebe04>] (flush_write_buffer+0x0/0x68) from [<c00ec1d8>] (sysfs_write_file+0x58/0x80) [21474615.495000] r8:c7acca80 r7:c79fff78 r6:000be408 r5:00000004 r4:c7a19ea0 [21474615.495000] [<c00ec180>] (sysfs_write_file+0x0/0x80) from [<c00a91b8>] (vfs_write+0xbc/0x14c) [21474615.495000] [<c00a90fc>] (vfs_write+0x0/0x14c) from [<c00a9774>] (sys_write+0x4c/0x7c) [21474615.495000] r7:00000004 r6:00000000 r5:00000000 r4:c7acca80 [21474615.495000] [<c00a9728>] (sys_write+0x0/0x7c) from [<c002dc20>] (ret_fast_syscall+0x0/0x2c) Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c249
1 files changed, 128 insertions, 121 deletions
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index a536638352c..6a77fd1cf08 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -238,7 +238,7 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
}
fiq_ipc.hdq_error = 0;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* all tx is done */
/* idle in input mode, it's pulled up by 10K */
s3c2410_gpio_cfgpin(fiq_ipc.hdq_gpio_pin, S3C2410_GPIO_INPUT);
@@ -256,7 +256,7 @@ FIQ_HANDLER_ENTRY(64, 64)
}
if (--hdq_ctr == 0) { /* timed out, error */
fiq_ipc.hdq_error = 1;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* abort */
}
break;
@@ -274,7 +274,9 @@ FIQ_HANDLER_ENTRY(64, 64)
if (--hdq_bit == 0) {
fiq_ipc.hdq_error = 0;
- fiq_ipc.hdq_transaction_ctr++; /* done */
+ fiq_ipc.hdq_transaction_ctr =
+ fiq_ipc.hdq_request_ctr;
+
hdq_state = HDQB_IDLE;
} else
hdq_state = HDQB_DATA_RX_HIGH;
@@ -288,7 +290,7 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
/* timed out, error */
fiq_ipc.hdq_error = 2;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* abort */
break;
@@ -305,7 +307,8 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
/* timed out, error */
fiq_ipc.hdq_error = 3;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
+
/* we're in input mode already */
hdq_state = HDQB_IDLE; /* abort */
break;
@@ -844,8 +847,8 @@ static void gta02_fiq_attach_child_devices(struct device *parent_device)
static struct resource sc32440_fiq_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
- .start = IRQ_TIMER3,
- .end = IRQ_TIMER3,
+ .start = IRQ_TIMER1,
+ .end = IRQ_TIMER1,
},
};
@@ -1090,17 +1093,22 @@ static struct glamo_spigpio_info glamo_spigpio_cfg = {
/* #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;
+
+/*
+ * generic SPI RX and TX bitbang
+ * only call with interrupts off!
+ */
-void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
+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;
+ u8 shifter = 0;
+ int n;
unsigned long flags;
-#ifdef DEBUG_SPEW_MS
- s8 x, y, z;
-#endif
+ unsigned long other_cs;
local_irq_save(flags);
@@ -1110,53 +1118,96 @@ 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_top == pdata)
+ other_cs = lis302_pdata_bottom.pin_chip_select;
+ else
+ 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 - n)) & 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);
- shifter <<= 1;
- if (s3c2410_gpio_getpin(pdata->pin_miso))
- shifter |= 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);
+ 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_chip_select, 1);
+ s3c2410_gpio_setpin(other_cs, 1);
+
local_irq_restore(flags);
+}
+
+
+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
}
@@ -1183,103 +1234,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,
},
};
@@ -1591,7 +1597,8 @@ static struct platform_device *gta02_devices_pmu_children[] = {
&gta02_pm_gsm_dev,
&gta02_sdio_dev,
&gta02_pm_usbhost_dev,
- &s3c_device_spi_acc, /* input 2 and 3 */
+ &s3c_device_spi_acc1, /* input 2 */
+ &s3c_device_spi_acc2, /* input 3 */
&gta02_button_dev, /* input 4 */
&gta02_resume_reason_device,
};
@@ -1626,8 +1633,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;