[PATCH] fix-lis302dl-isr-lock.patch

Andy Green andy at openmoko.com
Mon Mar 31 11:28:55 CEST 2008


It seems that the two accelermoter interrupts can interrupt each other after some
time and destroy one interrupt acknowledge action by starting an acknowledge for
the second accelermoter partway through.  Since the two are edge-triggered interrupts
after this happens we do not see any more interrupts from the one whose acknowledge
was broken.

This patch protects the acknowldge / poll ISR with a spinlock that defers interrupt
acknowledge by the processor until the service for the first accelerometer is
completed.

Signed-off-by: Andy Green <andy at openmoko.com>
---

 arch/arm/mach-s3c2440/mach-gta02.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)


diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 53a11e7..00cae16 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -85,6 +85,9 @@
 #include <linux/gta02_hdq.h>
 #include <linux/bq27000_battery.h>
 
+/* arbitrates which sensor IRQ owns the shared SPI bus */
+static spinlock_t motion_irq_lock;
+
 /* define FIQ IPC struct */
 /*
  * contains stuff FIQ ISR modifies and normal kernel code can see and use
@@ -876,8 +879,9 @@ static struct platform_device gta01_led_dev = {
  * Foreground / interrupt arbitration is okay because the interrupts are
  * disabled around all the foreground SPI code.
  *
- * Interrupt / Interrupt arbitration is okay because the interrupts are
- * at the same priority (I think)
+ * 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.
  */
@@ -890,10 +894,12 @@ void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
 	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);
@@ -931,6 +937,7 @@ void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
 		}
 	}
 	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);
@@ -1303,6 +1310,8 @@ static void __init gta02_machine_init(void)
 
 	printk(KERN_INFO"GTA02 PCB rev = 0x%03X\n", gta02_get_pcb_revision());
 
+	spin_lock_init(&motion_irq_lock);
+
 	s3c_device_usb.dev.platform_data = &gta02_usb_info;
 	s3c_device_nand.dev.platform_data = &gta02_nand_info;
 	s3c_device_sdi.dev.platform_data = &gta02_mmc_cfg;





More information about the openmoko-kernel mailing list