From 39c9873cdf522cd4356bf1a0de5143ac91e24d21 Mon Sep 17 00:00:00 2001
From: Colin Cross <ccross@android.com>
Date: Tue, 15 Mar 2011 17:37:39 -0700
Subject: [PATCH] misc: l3g4200d: Make enable powerup delay asynchronous

Moves enable_irq in l3g4200d_enable into a delayed work function
to avoid blocking the enable ioctl for the powerup delay.

Change-Id: Ic93a3526a452a5945e75364fe06200f5626c1eef
Signed-off-by: Colin Cross <ccross@android.com>
---
 drivers/misc/l3g4200d.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/l3g4200d.c b/drivers/misc/l3g4200d.c
index ce85f33a92aa..71c7574227cb 100755
--- a/drivers/misc/l3g4200d.c
+++ b/drivers/misc/l3g4200d.c
@@ -87,6 +87,7 @@ struct l3g4200d_data {
 	int hw_initialized;
 	atomic_t enabled;
 	struct regulator *regulator;
+	struct delayed_work enable_work;
 };
 
 struct gyro_val {
@@ -265,8 +266,6 @@ static int l3g4200d_device_power_on(struct l3g4200d_data *gyro)
 	if (err < 0)
 		dev_err(&gyro->client->dev, "soft power on failed\n");
 
-	msleep(L3G4200D_PU_DELAY);
-
 	return 0;
 }
 
@@ -354,6 +353,16 @@ static int l3g4200d_flush_gyro_data(struct l3g4200d_data *gyro)
 	return -EIO;
 }
 
+static void l3g4200d_enable_work_func(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct l3g4200d_data *gyro =
+		container_of(dwork, struct l3g4200d_data, enable_work);
+
+	l3g4200d_flush_gyro_data(gyro);
+	enable_irq(gyro->client->irq);
+}
+
 static int l3g4200d_enable(struct l3g4200d_data *gyro)
 {
 	int err;
@@ -374,8 +383,8 @@ static int l3g4200d_enable(struct l3g4200d_data *gyro)
 
 		/* do not report noise at IC power-up
 		 * flush data before enabling irq */
-		l3g4200d_flush_gyro_data(gyro);
-		enable_irq(gyro->client->irq);
+		schedule_delayed_work(&gyro->enable_work,
+			msecs_to_jiffies(L3G4200D_PU_DELAY));
 	}
 	return 0;
 err0:
@@ -386,7 +395,8 @@ err0:
 static int l3g4200d_disable(struct l3g4200d_data *gyro)
 {
 	if (atomic_cmpxchg(&gyro->enabled, 1, 0)) {
-		disable_irq(gyro->client->irq);
+		if (!cancel_delayed_work_sync(&gyro->enable_work))
+			disable_irq(gyro->client->irq);
 		l3g4200d_device_power_off(gyro);
 		if (gyro->regulator) {
 			regulator_disable(gyro->regulator);
@@ -618,6 +628,7 @@ static int l3g4200d_probe(struct i2c_client *client,
 	/* As default, do not report information */
 	atomic_set(&gyro->enabled, 0);
 	gyro->hw_initialized = false;
+	INIT_DELAYED_WORK(&gyro->enable_work, l3g4200d_enable_work_func);
 
 	err = l3g4200d_input_init(gyro);
 	if (err < 0)
-- 
2.34.1