diff mbox

[v2,2/2] Input: TWL4030-vibra: use dynamic workqueue

Message ID 1266935279-331-2-git-send-email-ext-jari.vanhala@nokia.com
State New, archived
Headers show

Commit Message

Jari Vanhala Feb. 23, 2010, 2:27 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 50f7537..0d5be20 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -45,6 +45,7 @@  struct vibra_info {
 	struct workqueue_struct *workqueue;
 	struct work_struct	play_work;
 	spinlock_t		lock; /* for workqueue */
+	int			users;
 
 	bool			enabled;
 	int			speed;
@@ -153,6 +154,49 @@  out:
 	return 0;
 }
 
+static int twl4030_vibra_open(struct input_dev *input)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	if (info->workqueue == NULL) {
+		info->workqueue = create_singlethread_workqueue("vibra");
+		if (info->workqueue == NULL) {
+			dev_err(&input->dev, "couldn't create workqueue\n");
+			return -ENOMEM;
+		}
+	}
+
+	info->users++;
+	return 0;
+}
+
+static void twl4030_vibra_wq_destroy(struct vibra_info *info)
+{
+	struct workqueue_struct *wq;
+
+	spin_lock(&info->lock);
+	wq = info->workqueue;
+	info->workqueue = NULL;
+	spin_unlock(&info->lock);
+
+	if (wq) {
+		cancel_work_sync(&info->play_work);
+		INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
+		destroy_workqueue(wq);
+	}
+
+	if (info->enabled)
+		vibra_disable(info);
+}
+
+static void twl4030_vibra_close(struct input_dev *input)
+{
+	struct vibra_info *info = input_get_drvdata(input);
+
+	if (!(--info->users))
+		twl4030_vibra_wq_destroy(info);
+}
+
 /*** Module ***/
 #if CONFIG_PM
 static int twl4030_vibra_suspend(struct device *dev)
@@ -197,12 +241,8 @@  static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, info);
 
-	info->workqueue = create_singlethread_workqueue("vibra");
-	if (info->workqueue == NULL) {
-		dev_err(&pdev->dev, "couldn't create workqueue\n");
-		ret = -ENOMEM;
-		goto err_kzalloc;
-	}
+	info->workqueue = NULL;
+	info->users = 0;
 	INIT_WORK(&info->play_work, vibra_play_work);
 	spin_lock_init(&info->lock);
 
@@ -210,13 +250,15 @@  static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 	if (info->input_dev == NULL) {
 		dev_err(&pdev->dev, "couldn't allocate input device\n");
 		ret = -ENOMEM;
-		goto err_workq;
+		goto err_kzalloc;
 	}
 	input_set_drvdata(info->input_dev, info);
 
 	info->input_dev->name = "twl4030:vibrator";
 	info->input_dev->id.version = 1;
 	info->input_dev->dev.parent = pdev->dev.parent;
+	info->input_dev->open = twl4030_vibra_open;
+	info->input_dev->close = twl4030_vibra_close;
 	set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
 	ret = input_register_device(info->input_dev);
@@ -239,8 +281,6 @@  err_ireg:
 	info->input_dev = NULL;
 err_ialloc:
 	input_free_device(info->input_dev);
-err_workq:
-	destroy_workqueue(info->workqueue);
 err_kzalloc:
 	kfree(info);
 	return ret;
@@ -249,17 +289,8 @@  err_kzalloc:
 static int __devexit twl4030_vibra_remove(struct platform_device *pdev)
 {
 	struct vibra_info *info = platform_get_drvdata(pdev);
-	struct workqueue_struct *wq;
-
-	spin_lock(&info->lock);
-	wq = info->workqueue;
-	info->workqueue = NULL;
-	spin_unlock(&info->lock);
 
-	cancel_work_sync(&info->play_work);
-	destroy_workqueue(wq);
-	if (info->enabled)
-		vibra_disable(info);
+	twl4030_vibra_wq_destroy(info);
 	/* this also free ff-memless which (in turn) kfree info */
 	input_unregister_device(info->input_dev);