From e58348b75db2060bf7079d007cc34d25aa3e35e8 Mon Sep 17 00:00:00 2001
From: Holger Freyther <zecke@openmoko.org>
Date: Fri, 10 Oct 2008 15:43:15 +0200
Subject: [PATCH] [lis302dl] Switch from mutex to spinlock because we have to
     https://docs.openmoko.org/trac/attachment/ticket/1597/dmesg-removing-from-wall-charger-pluging-into-desktop-usb
     shows a nice mutex message that we might sleep in a mutex which is
     forbidden. Switch everything to a spinlock... and as irq's are disabled
     everything should be fine. We have done so in the led and vibrator driver
     as wel.

Signed-Off-By: Holger Hans Peter Freyther <zecke@openmoko.org>
---
 drivers/input/misc/lis302dl.c |   56 +++++++++++++++++++---------------------
 include/linux/lis302dl.h      |    2 +-
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index b01ca04..10f6035 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -62,10 +62,11 @@ static 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)
 {
 	u_int8_t ret;
+	unsigned long flags;
 
-	mutex_lock(&lis->lock);
+	spin_lock_irqsave(&lis->lock, flags);
 	ret = __reg_read(lis, reg);
-	mutex_unlock(&lis->lock);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	return ret;
 }
@@ -85,10 +86,11 @@ static 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)
 {
 	int ret;
+	unsigned long flags;
 
-	mutex_lock(&lis->lock);
+	spin_lock_irqsave(&lis->lock, flags);
 	ret = __reg_write(lis, reg, val);
-	mutex_unlock(&lis->lock);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	return ret;
 }
@@ -98,17 +100,18 @@ static int reg_set_bit_mask(struct lis302dl_info *lis,
 {
 	int ret;
 	u_int8_t tmp;
+	unsigned long flags;
 
 	val &= mask;
 
-	mutex_lock(&lis->lock);
+	spin_lock_irqsave(&lis->lock, flags);
 
 	tmp = __reg_read(lis, reg);
 	tmp &= ~mask;
 	tmp |= val;
 	ret = __reg_write(lis, reg, tmp);
 
-	mutex_unlock(&lis->lock);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	return ret;
 }
@@ -230,12 +233,12 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
 	char *end = buf;
 	unsigned long flags;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 
 	for (n = 0; n < sizeof(reg); n++)
 		reg[n] = reg_read(lis, n);
 
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	for (n = 0; n < sizeof(reg); n += 16) {
 		hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
@@ -312,7 +315,7 @@ static ssize_t set_freefall_common(int which, struct device *dev,
 	/* Parse the input */
 	if (strcmp(buf, "0\n") == 0) {
 		/* Turn off the interrupt */
-		local_irq_save(flags);
+		spin_lock_irqsave(&lis->lock, flags);
 		if (lis->flags & LIS302DL_F_IRQ_WAKE)
 			disable_irq_wake(lis->spi_dev->irq);
 		lis302dl_int_mode(lis->spi_dev, which,
@@ -328,7 +331,7 @@ static ssize_t set_freefall_common(int which, struct device *dev,
 			reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
 							  LIS302DL_CTRL1_PD, 0);
 
-		local_irq_restore(flags);
+		spin_unlock_irqrestore(&lis->lock, flags);
 
 		return count;
 	}
@@ -354,7 +357,7 @@ static ssize_t set_freefall_common(int which, struct device *dev,
 	z_hi = z > 0 ? LIS302DL_FFWUCFG_ZHIE : 0;
 
 	/* Setup the configuration registers */
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 	reg_write(lis, r_cfg, 0); /* First zero to get to a known state */
 	reg_write(lis, r_cfg,
 		(and_events ? LIS302DL_FFWUCFG_AOI : 0) |
@@ -373,7 +376,7 @@ static ssize_t set_freefall_common(int which, struct device *dev,
 	lis->flags |= flag_mask | LIS302DL_F_IRQ_WAKE;
 	reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
 			LIS302DL_CTRL1_PD);
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	return count;
 }
@@ -476,13 +479,9 @@ 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_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);
-
 	lis->flags |= LIS302DL_F_INPUT_OPEN;
 
 	/* kick it off -- since we are edge triggered, if we missed the edge
@@ -499,7 +498,7 @@ static void lis302dl_input_close(struct input_dev *inp)
 			 LIS302DL_CTRL1_Zen;
 	unsigned long flags;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 
 	/* since the input core already serializes access and makes sure we
 	 * only see close() for the close of the last user, we can safely
@@ -513,7 +512,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);
+	spin_unlock_irqrestore(&lis->lock, flags);
 }
 
 /* get the device to reload its coefficients from EEPROM and wait for it
@@ -546,9 +545,8 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 	if (!lis)
 		return -ENOMEM;
 
-	local_irq_save(flags);
-
-	mutex_init(&lis->lock);
+	spin_lock_init(&lis->lock);
+	spin_lock_irqsave(&lis->lock, flags);
 	lis->spi_dev = spi;
 
 	spi_set_drvdata(spi, lis);
@@ -654,7 +652,7 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
 			lis->spi_dev->irq);
 		goto bail_inp_reg;
 	}
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 	return 0;
 
 bail_inp_reg:
@@ -665,7 +663,7 @@ bail_sysfs:
 	sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
 bail_free_lis:
 	kfree(lis);
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 	return rc;
 }
 
@@ -675,11 +673,11 @@ static int __devexit lis302dl_remove(struct spi_device *spi)
 	unsigned long flags;
 
 	/* Reset and power down the device */
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 	reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
 	reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
 	reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	/* Cleanup resources */
 	free_irq(lis->spi_dev->irq, lis);
@@ -706,7 +704,7 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
 		return 0;
 
 	disable_irq(lis->spi_dev->irq);
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 
 	/*
 	 * When we share SPI over multiple sensors, there is a race here
@@ -754,7 +752,7 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
 	/* place our IO to the device in sleep-compatible states */
 	(lis->pdata->lis302dl_suspend_io)(lis, 0);
 
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&lis->lock, flags);
 
 	return 0;
 }
@@ -768,7 +766,7 @@ static int lis302dl_resume(struct spi_device *spi)
 		lis->flags & LIS302DL_F_WUP_CLICK)
 		return 0;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&lis->lock, flags);
 
 	/* get our IO to the device back in operational states */
 	(lis->pdata->lis302dl_suspend_io)(lis, 1);
@@ -816,7 +814,7 @@ 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);
+	spin_unlock_irqrestore(&lis->lock, flags);
 	enable_irq(lis->spi_dev->irq);
 
 	return 0;
diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
index 7daa8b3..c3ecbb7 100644
--- a/include/linux/lis302dl.h
+++ b/include/linux/lis302dl.h
@@ -23,7 +23,7 @@ struct lis302dl_info {
 	struct lis302dl_platform_data *pdata;
 	struct spi_device *spi_dev;
 	struct input_dev *input_dev;
-	struct mutex lock;
+	spinlock_t lock;
 	unsigned int flags;
 	u_int8_t regs[0x40];
 };
-- 
1.5.4.3

