Input: tsc2005 - rework driver initialization code

We need to make sure we have time/work initialized before requesting and
enabling interrupts, otherwise we might start using them way too early.

Tested-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 09cbcb0..de170e9 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -495,6 +495,16 @@
 	mutex_unlock(&ts->mutex);
 }
 
+static struct attribute *tsc2005_attrs[] = {
+	&dev_attr_disable.attr,
+	&dev_attr_selftest.attr,
+	NULL
+};
+
+static struct attribute_group tsc2005_attr_group = {
+	.attrs = tsc2005_attrs,
+};
+
 static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
 {
 	tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0);
@@ -509,144 +519,130 @@
 	spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
 }
 
-static struct attribute *tsc2005_attrs[] = {
-	&dev_attr_disable.attr,
-	&dev_attr_selftest.attr,
-	NULL
-};
-
-static struct attribute_group tsc2005_attr_group = {
-	.attrs = tsc2005_attrs,
-};
-
-static int __devinit tsc2005_setup(struct tsc2005 *ts,
-				   struct tsc2005_platform_data *pdata)
-{
-	int r;
-	int fudge_x;
-	int fudge_y;
-	int fudge_p;
-	int p_max;
-	int x_max;
-	int y_max;
-
-	mutex_init(&ts->mutex);
-
-	tsc2005_setup_spi_xfer(ts);
-
-	init_timer(&ts->penup_timer);
-	setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
-	INIT_WORK(&ts->penup_work, tsc2005_penup_work);
-
-	fudge_x		= pdata->ts_x_fudge	   ? : 4;
-	fudge_y		= pdata->ts_y_fudge	   ? : 8;
-	fudge_p		= pdata->ts_pressure_fudge ? : 2;
-	x_max		= pdata->ts_x_max	   ? : MAX_12BIT;
-	y_max		= pdata->ts_y_max	   ? : MAX_12BIT;
-	p_max		= pdata->ts_pressure_max   ? : MAX_12BIT;
-	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	   ? : 280;
-	ts->esd_timeout	= pdata->esd_timeout_ms;
-	ts->set_reset	= pdata->set_reset;
-
-	ts->idev = input_allocate_device();
-	if (ts->idev == NULL)
-		return -ENOMEM;
-	ts->idev->name = "TSC2005 touchscreen";
-	snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts",
-		 dev_name(&ts->spi->dev));
-	ts->idev->phys = ts->phys;
-	ts->idev->id.bustype = BUS_SPI;
-	ts->idev->dev.parent = &ts->spi->dev;
-	ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
-	ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
-	ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
-	input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0);
-	input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0);
-	input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0);
-
-	r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler,
-				 tsc2005_irq_thread, IRQF_TRIGGER_RISING,
-				 "tsc2005", ts);
-	if (r) {
-		dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r);
-		goto err1;
-	}
-	set_irq_wake(ts->spi->irq, 1);
-
-	r = input_register_device(ts->idev);
-	if (r) {
-		dev_err(&ts->spi->dev, "input_register_device(): %d\n", r);
-		goto err2;
-	}
-
-	r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
-	if (r)
-		dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r);
-
-	tsc2005_start_scan(ts);
-
-	if (!ts->esd_timeout || !ts->set_reset)
-		goto done;
-
-	/* start the optional ESD watchdog */
-	setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts);
-	INIT_WORK(&ts->esd_work, tsc2005_esd_work);
-	mod_timer(&ts->esd_timer,
-		  round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout)));
-
-done:
-	return 0;
-
-err2:
-	free_irq(ts->spi->irq, ts);
-
-err1:
-	input_free_device(ts->idev);
-	return r;
-}
-
 static int __devinit tsc2005_probe(struct spi_device *spi)
 {
-	struct tsc2005_platform_data *pdata = spi->dev.platform_data;
+	const struct tsc2005_platform_data *pdata = spi->dev.platform_data;
 	struct tsc2005 *ts;
-	int r;
-
-	if (spi->irq < 0) {
-		dev_dbg(&spi->dev, "no irq\n");
-		return -ENODEV;
-	}
+	struct input_dev *input_dev;
+	unsigned int max_x, max_y, max_p;
+	unsigned int fudge_x, fudge_y, fudge_p;
+	int error;
 
 	if (!pdata) {
 		dev_dbg(&spi->dev, "no platform data\n");
 		return -ENODEV;
 	}
 
-	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-	if (ts == NULL)
-		return -ENOMEM;
+	fudge_x	= pdata->ts_x_fudge	   ? : 4;
+	fudge_y	= pdata->ts_y_fudge	   ? : 8;
+	fudge_p	= pdata->ts_pressure_fudge ? : 2;
+	max_x	= pdata->ts_x_max	   ? : MAX_12BIT;
+	max_y	= pdata->ts_y_max	   ? : MAX_12BIT;
+	max_p	= pdata->ts_pressure_max   ? : MAX_12BIT;
 
-	spi_set_drvdata(spi, ts);
-	ts->spi = spi;
-	spi->dev.power.power_state = PMSG_ON;
+	if (spi->irq <= 0) {
+		dev_dbg(&spi->dev, "no irq\n");
+		return -ENODEV;
+	}
+
 	spi->mode = SPI_MODE_0;
 	spi->bits_per_word = 8;
 	if (!spi->max_speed_hz)
 		spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ;
-	spi_setup(spi);
 
-	r = tsc2005_setup(ts, pdata);
-	if (r) {
-		kfree(ts);
-		spi_set_drvdata(spi, NULL);
+	error = spi_setup(spi);
+	if (error)
+		return error;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
 	}
-	return r;
+
+	ts->spi = spi;
+	ts->idev = input_dev;
+
+	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	? : 280;
+	ts->esd_timeout	= pdata->esd_timeout_ms;
+	ts->set_reset	= pdata->set_reset;
+
+	mutex_init(&ts->mutex);
+
+	setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
+	INIT_WORK(&ts->penup_work, tsc2005_penup_work);
+
+	setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts);
+	INIT_WORK(&ts->esd_work, tsc2005_esd_work);
+
+	tsc2005_setup_spi_xfer(ts);
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input-ts", dev_name(&spi->dev));
+
+	input_dev->name = "TSC2005 touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_SPI;
+	input_dev->dev.parent = &spi->dev;
+	input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
+
+	error = request_threaded_irq(spi->irq,
+				     tsc2005_irq_handler, tsc2005_irq_thread,
+				     IRQF_TRIGGER_RISING, "tsc2005", ts);
+	if (error) {
+		dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
+		goto err_free_mem;
+	}
+
+	spi_set_drvdata(spi, ts);
+	error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group);
+	if (error) {
+		dev_err(&spi->dev,
+			"Failed to create sysfs attributes, err: %d\n", error);
+		goto err_clear_drvdata;
+	}
+
+	error = input_register_device(ts->idev);
+	if (error) {
+		dev_err(&spi->dev,
+			"Failed to register input device, err: %d\n", error);
+		goto err_remove_sysfs;
+	}
+
+	tsc2005_start_scan(ts);
+
+	if (ts->esd_timeout && ts->set_reset) {
+		/* start the optional ESD watchdog */
+		mod_timer(&ts->esd_timer, round_jiffies(jiffies +
+					msecs_to_jiffies(ts->esd_timeout)));
+	}
+
+	set_irq_wake(spi->irq, 1);
+	return 0;
+
+err_remove_sysfs:
+	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
+err_clear_drvdata:
+	spi_set_drvdata(spi, NULL);
+	free_irq(spi->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return error;
 }
 
 static int __devexit tsc2005_remove(struct spi_device *spi)
 {
 	struct tsc2005 *ts = spi_get_drvdata(spi);
 
+	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
+
 	mutex_lock(&ts->mutex);
 	tsc2005_disable(ts);
 	mutex_unlock(&ts->mutex);
@@ -658,7 +654,6 @@
 	flush_work(&ts->esd_work);
 	flush_work(&ts->penup_work);
 
-	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
 	free_irq(ts->spi->irq, ts);
 	input_unregister_device(ts->idev);
 	kfree(ts);