All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
@ 2009-07-10  2:10 Joonyoung Shim
  2009-07-14  6:04 ` Dmitry Torokhov
  0 siblings, 1 reply; 9+ messages in thread
From: Joonyoung Shim @ 2009-07-10  2:10 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

The MELPAS MCS-5000 is the touchscreen controller. The overview of this
controller can see at the following website:

http://www.melfas.com/product/product01.asp?k_r=eng_

This driver is tested on s3c6410 NCP board and supports only the i2c
interface.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
---
Dear Dmitry,

I sent the patch v2, but couldn't get any response.
This patch v3 is updated a little bit from v2.

I have one question. The MCS-5000 controller don't support PRESSURE, so
i removed a fake PRESSURE report on driver, but tslib v1.0
(http://tslib.berlios.de) require the PRESSURE report from driver. I
wonder whether it is make sense to report a fake PRESSURE for tslib.


Change log:
v2: updated as per feedback for v1
v3: add platform_data checking before call set_pin() on probe function
    change #ifdef CONFIG_PM position

Thank you.

 drivers/input/touchscreen/Kconfig      |   12 +
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/mcs5000_ts.c |  374 ++++++++++++++++++++++++++++++++
 include/linux/i2c/mcs5000_ts.h         |   11 +
 4 files changed, 398 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/mcs5000_ts.c
 create mode 100644 include/linux/i2c/mcs5000_ts.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 72e2712..3bc66db 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -498,4 +498,16 @@ config TOUCHSCREEN_W90X900
 	  To compile this driver as a module, choose M here: the
 	  module will be called w90p910_ts.
 
+config TOUCHSCREEN_MCS5000
+	tristate "MELFAS MCS-5000 touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have the MELFAS MCS-5000 touchscreen controller
+	  chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mcs5000_ts.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3e1c5e0..91e820f 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -40,3 +40,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL)	+= atmel-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MCS5000)	+= mcs5000_ts.o
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
new file mode 100644
index 0000000..d6c1a94
--- /dev/null
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -0,0 +1,374 @@
+/*
+ * mcs5000_ts.c - Touch screen driver for MELFAS MCS-5000 controller
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * Based on wm97xx-core.c
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs5000_ts.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+
+/* Registers */
+#define MCS5000_TS_STATUS		0x00
+#define STATUS_OFFSET			0
+#define STATUS_NO			(0 << STATUS_OFFSET)
+#define STATUS_INIT			(1 << STATUS_OFFSET)
+#define STATUS_SENSING			(2 << STATUS_OFFSET)
+#define STATUS_COORD			(3 << STATUS_OFFSET)
+#define STATUS_GESTURE			(4 << STATUS_OFFSET)
+#define ERROR_OFFSET			4
+#define ERROR_NO			(0 << ERROR_OFFSET)
+#define ERROR_POWER_ON_RESET		(1 << ERROR_OFFSET)
+#define ERROR_INT_RESET			(2 << ERROR_OFFSET)
+#define ERROR_EXT_RESET			(3 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_ADDRESS	(8 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_VALUE		(9 << ERROR_OFFSET)
+
+#define MCS5000_TS_OP_MODE		0x01
+#define RESET_OFFSET			0
+#define RESET_NO			(0 << RESET_OFFSET)
+#define RESET_EXT_SOFT			(1 << RESET_OFFSET)
+#define OP_MODE_OFFSET			1
+#define OP_MODE_SLEEP			(0 << OP_MODE_OFFSET)
+#define OP_MODE_ACTIVE			(1 << OP_MODE_OFFSET)
+#define GESTURE_OFFSET			4
+#define GESTURE_DISABLE			(0 << GESTURE_OFFSET)
+#define GESTURE_ENABLE			(1 << GESTURE_OFFSET)
+#define PROXIMITY_OFFSET		5
+#define PROXIMITY_DISABLE		(0 << PROXIMITY_OFFSET)
+#define PROXIMITY_ENABLE		(1 << PROXIMITY_OFFSET)
+#define SCAN_MODE_OFFSET		6
+#define SCAN_MODE_INTERRUPT		(0 << SCAN_MODE_OFFSET)
+#define SCAN_MODE_POLLING		(1 << SCAN_MODE_OFFSET)
+#define REPORT_RATE_OFFSET		7
+#define REPORT_RATE_40			(0 << REPORT_RATE_OFFSET)
+#define REPORT_RATE_80			(1 << REPORT_RATE_OFFSET)
+
+#define MCS5000_TS_SENS_CTL		0x02
+#define MCS5000_TS_FILTER_CTL		0x03
+#define PRI_FILTER_OFFSET		0
+#define SEC_FILTER_OFFSET		4
+
+#define MCS5000_TS_X_SIZE_UPPER		0x08
+#define MCS5000_TS_X_SIZE_LOWER		0x09
+#define MCS5000_TS_Y_SIZE_UPPER		0x0A
+#define MCS5000_TS_Y_SIZE_LOWER		0x0B
+
+#define MCS5000_TS_INPUT_INFO		0x10
+#define INPUT_TYPE_OFFSET		0
+#define INPUT_TYPE_NONTOUCH		(0 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_SINGLE		(1 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_DUAL			(2 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PALM			(3 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PROXIMITY		(7 << INPUT_TYPE_OFFSET)
+#define GESTURE_CODE_OFFSET		3
+#define GESTURE_CODE_NO			(0 << GESTURE_CODE_OFFSET)
+
+#define MCS5000_TS_X_POS_UPPER		0x11
+#define MCS5000_TS_X_POS_LOWER		0x12
+#define MCS5000_TS_Y_POS_UPPER		0x13
+#define MCS5000_TS_Y_POS_LOWER		0x14
+#define MCS5000_TS_Z_POS		0x15
+#define MCS5000_TS_WIDTH		0x16
+#define MCS5000_TS_GESTURE_VAL		0x17
+#define MCS5000_TS_MODULE_REV		0x20
+#define MCS5000_TS_FIRMWARE_VER		0x21
+
+/* Touchscreen absolute values */
+#define MCS5000_MAX_XC			0x3ff
+#define MCS5000_MAX_YC			0x3ff
+
+enum mcs5000_ts_read_offset {
+	READ_INPUT_INFO,
+	READ_X_POS_UPPER,
+	READ_X_POS_LOWER,
+	READ_Y_POS_UPPER,
+	READ_Y_POS_LOWER,
+	READ_BLOCK_SIZE,
+};
+
+/* Each client has this additional data */
+struct mcs5000_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct work_struct ts_event_work;
+	struct mcs5000_ts_platform_data *platform_data;
+
+	unsigned int irq;
+	atomic_t irq_disable;
+};
+
+static struct i2c_driver mcs5000_ts_driver;
+
+static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
+{
+	struct i2c_client *client = data->client;
+	u8 buffer[READ_BLOCK_SIZE];
+	int err;
+	int x;
+	int y;
+
+	err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
+			READ_BLOCK_SIZE, buffer);
+	if (err < 0) {
+		dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
+		return;
+	}
+
+	switch (buffer[READ_INPUT_INFO]) {
+	case INPUT_TYPE_NONTOUCH:
+		input_report_key(data->input_dev, BTN_TOUCH, 0);
+		input_sync(data->input_dev);
+		break;
+	case INPUT_TYPE_SINGLE:
+		x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
+		y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
+
+		input_report_key(data->input_dev, BTN_TOUCH, 1);
+		input_report_abs(data->input_dev, ABS_X, x);
+		input_report_abs(data->input_dev, ABS_Y, y);
+		input_sync(data->input_dev);
+		break;
+	case INPUT_TYPE_DUAL:
+		/* TODO */
+		break;
+	case INPUT_TYPE_PALM:
+		/* TODO */
+		break;
+	case INPUT_TYPE_PROXIMITY:
+		/* TODO */
+		break;
+	default:
+		dev_err(&client->dev, "Unknown ts input type %d\n",
+				buffer[READ_INPUT_INFO]);
+		break;
+	}
+}
+
+static void mcs5000_ts_irq_worker(struct work_struct *work)
+{
+	struct mcs5000_ts_data *data = container_of(work,
+			struct mcs5000_ts_data, ts_event_work);
+
+	mcs5000_ts_input_read(data);
+
+	atomic_dec(&data->irq_disable);
+	enable_irq(data->irq);
+}
+
+static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
+{
+	struct mcs5000_ts_data *data = dev_id;
+
+	if (!work_pending(&data->ts_event_work)) {
+		disable_irq_nosync(data->irq);
+		atomic_inc(&data->irq_disable);
+		schedule_work(&data->ts_event_work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mcs5000_ts_input_init(struct mcs5000_ts_data *data)
+{
+	struct input_dev *input_dev;
+	int ret = 0;
+
+	INIT_WORK(&data->ts_event_work, mcs5000_ts_irq_worker);
+
+	data->input_dev = input_allocate_device();
+	if (data->input_dev == NULL) {
+		ret = -ENOMEM;
+		goto err_input;
+	}
+
+	input_dev = data->input_dev;
+	input_dev->name = "MELPAS MCS-5000 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &data->client->dev;
+	set_bit(EV_ABS, input_dev->evbit);
+	set_bit(ABS_X, input_dev->absbit);
+	set_bit(ABS_Y, input_dev->absbit);
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
+
+	ret = input_register_device(data->input_dev);
+	if (ret < 0)
+		goto err_register;
+
+	ret = request_irq(data->irq, mcs5000_ts_interrupt, IRQF_TRIGGER_LOW,
+			"mcs5000_ts_input", data);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed to register interrupt\n");
+		goto err_irq;
+	}
+
+	input_set_drvdata(input_dev, data);
+
+	return 0;
+err_irq:
+	input_unregister_device(data->input_dev);
+	data->input_dev = NULL;
+err_register:
+	input_free_device(data->input_dev);
+err_input:
+	return ret;
+}
+
+static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct mcs5000_ts_platform_data *platform_data = data->platform_data;
+
+	/* Touch reset & sleep mode */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
+			RESET_EXT_SOFT | OP_MODE_SLEEP);
+
+	/* Touch size */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
+			platform_data->x_size >> 8);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
+			platform_data->x_size & 0xff);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
+			platform_data->y_size >> 8);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
+			platform_data->y_size & 0xff);
+
+	/* Touch active mode & 80 report rate */
+	i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
+			OP_MODE_ACTIVE | REPORT_RATE_80);
+}
+
+static int __devinit mcs5000_ts_probe(struct i2c_client *client,
+		const struct i2c_device_id *idp)
+{
+	struct mcs5000_ts_data *data;
+	int ret;
+
+	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Failed to allocate driver data\n");
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	data->client = client;
+	data->platform_data = client->dev.platform_data;
+	data->irq = client->irq;
+	atomic_set(&data->irq_disable, 0);
+
+	i2c_set_clientdata(client, data);
+
+	if (data->platform_data && data->platform_data->set_pin)
+		data->platform_data->set_pin();
+
+	ret = mcs5000_ts_input_init(data);
+	if (ret)
+		goto exit_free;
+
+	mcs5000_ts_phys_init(data);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+	i2c_set_clientdata(client, NULL);
+exit:
+	return ret;
+}
+
+static int __devexit mcs5000_ts_remove(struct i2c_client *client)
+{
+	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
+
+	free_irq(data->irq, data);
+	cancel_work_sync(&data->ts_event_work);
+
+	/*
+	 * If work indeed has been cancelled, disable_irq() will have been left
+	 * unbalanced from mcs5000_ts_interrupt().
+	 */
+	while (atomic_dec_return(&data->irq_disable) >= 0)
+		enable_irq(data->irq);
+
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	i2c_set_clientdata(client, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	/* Touch sleep mode */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
+
+	return 0;
+}
+
+static int mcs5000_ts_resume(struct i2c_client *client)
+{
+	struct mcs5000_ts_data *data;
+
+	data = i2c_get_clientdata(client);
+	mcs5000_ts_phys_init(data);
+
+	return 0;
+}
+#else
+#define mcs5000_ts_suspend	NULL
+#define mcs5000_ts_resume	NULL
+#endif
+
+static const struct i2c_device_id mcs5000_ts_id[] = {
+	{ "mcs5000_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
+
+static struct i2c_driver mcs5000_ts_driver = {
+	.driver = {
+		.name = "mcs5000_ts",
+	},
+	.probe		= mcs5000_ts_probe,
+	.remove		= __devexit_p(mcs5000_ts_remove),
+	.suspend	= mcs5000_ts_suspend,
+	.resume		= mcs5000_ts_resume,
+	.id_table	= mcs5000_ts_id,
+};
+
+static int __init mcs5000_ts_init(void)
+{
+	return i2c_add_driver(&mcs5000_ts_driver);
+}
+
+static void __exit mcs5000_ts_exit(void)
+{
+	i2c_del_driver(&mcs5000_ts_driver);
+}
+
+module_init(mcs5000_ts_init);
+module_exit(mcs5000_ts_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Touch screen driver for MELFAS MCS-5000 controller");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c/mcs5000_ts.h b/include/linux/i2c/mcs5000_ts.h
new file mode 100644
index 0000000..69d92b6
--- /dev/null
+++ b/include/linux/i2c/mcs5000_ts.h
@@ -0,0 +1,11 @@
+#ifndef __LINUX_MCS5000_TS_H
+#define __LINUX_MCS5000_TS_H
+
+/* platform data for the MELFAS MCS5000 touchscreen driver */
+struct mcs5000_ts_platform_data {
+	void (*set_pin)(void);
+	int x_size;
+	int y_size;
+};
+
+#endif	/* __LINUX_MCS5000_TS_H */
-- 
1.6.0.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-10  2:10 [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller Joonyoung Shim
@ 2009-07-14  6:04 ` Dmitry Torokhov
  2009-07-14  6:47   ` Marek Szyprowski
  2009-07-15  7:51   ` Joonyoung Shim
  0 siblings, 2 replies; 9+ messages in thread
From: Dmitry Torokhov @ 2009-07-14  6:04 UTC (permalink / raw)
  To: Joonyoung Shim; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

Hi Joonyoung,

On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
> controller can see at the following website:
> 
> http://www.melfas.com/product/product01.asp?k_r=eng_
> 
> This driver is tested on s3c6410 NCP board and supports only the i2c
> interface.
> 
> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> ---
> Dear Dmitry,
> 
> I sent the patch v2, but couldn't get any response.
> This patch v3 is updated a little bit from v2.
> 

While I was sittign on the patch mainline acquired threaded IRQ support
which fits the bill here and simplifies logic quite a bit, could you
please try the patch below and tell me if the touchscreen still works?

> I have one question. The MCS-5000 controller don't support PRESSURE, so
> i removed a fake PRESSURE report on driver, but tslib v1.0
> (http://tslib.berlios.de) require the PRESSURE report from driver. I
> wonder whether it is make sense to report a fake PRESSURE for tslib.
> 

I believe the adjustments to use BTN_TOUCH in absebse of ABS_PRESSURE
has been applied to tslib, you need to talk to the maintainers about
releasing updated version instead of adding fake events to the kernel.

Thanks.

-- 
Dmitry


Input: mcs5000_ts - use threaded IRQs

From: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Threaded IRQs are exactly what this driver needs since it communicates
with the device over I2C bus, which requires sleeping.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/input/touchscreen/mcs5000_ts.c |  162 +++++++++++---------------------
 1 files changed, 57 insertions(+), 105 deletions(-)


diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index d6c1a94..ff54ea9 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/irq.h>
-#include <linux/workqueue.h>
 
 /* Registers */
 #define MCS5000_TS_STATUS		0x00
@@ -105,17 +104,12 @@ enum mcs5000_ts_read_offset {
 struct mcs5000_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	struct work_struct ts_event_work;
-	struct mcs5000_ts_platform_data *platform_data;
-
-	unsigned int irq;
-	atomic_t irq_disable;
+	const struct mcs5000_ts_platform_data *platform_data;
 };
 
-static struct i2c_driver mcs5000_ts_driver;
-
-static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
+static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
 {
+	struct mcs5000_ts_data *data = dev_id;
 	struct i2c_client *client = data->client;
 	u8 buffer[READ_BLOCK_SIZE];
 	int err;
@@ -126,7 +120,7 @@ static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
 			READ_BLOCK_SIZE, buffer);
 	if (err < 0) {
 		dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
-		return;
+		goto out;
 	}
 
 	switch (buffer[READ_INPUT_INFO]) {
@@ -134,6 +128,7 @@ static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
 		input_report_key(data->input_dev, BTN_TOUCH, 0);
 		input_sync(data->input_dev);
 		break;
+
 	case INPUT_TYPE_SINGLE:
 		x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
 		y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
@@ -143,98 +138,40 @@ static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
 		input_report_abs(data->input_dev, ABS_Y, y);
 		input_sync(data->input_dev);
 		break;
+
 	case INPUT_TYPE_DUAL:
 		/* TODO */
 		break;
+
 	case INPUT_TYPE_PALM:
 		/* TODO */
 		break;
+
 	case INPUT_TYPE_PROXIMITY:
 		/* TODO */
 		break;
+
 	default:
 		dev_err(&client->dev, "Unknown ts input type %d\n",
 				buffer[READ_INPUT_INFO]);
 		break;
 	}
-}
-
-static void mcs5000_ts_irq_worker(struct work_struct *work)
-{
-	struct mcs5000_ts_data *data = container_of(work,
-			struct mcs5000_ts_data, ts_event_work);
-
-	mcs5000_ts_input_read(data);
-
-	atomic_dec(&data->irq_disable);
-	enable_irq(data->irq);
-}
-
-static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
-{
-	struct mcs5000_ts_data *data = dev_id;
-
-	if (!work_pending(&data->ts_event_work)) {
-		disable_irq_nosync(data->irq);
-		atomic_inc(&data->irq_disable);
-		schedule_work(&data->ts_event_work);
-	}
 
+ out:
+	enable_irq(irq);
 	return IRQ_HANDLED;
 }
 
-static int mcs5000_ts_input_init(struct mcs5000_ts_data *data)
+static irqreturn_t mcs5000_ts_hardirq(int irq, void *dev_id)
 {
-	struct input_dev *input_dev;
-	int ret = 0;
-
-	INIT_WORK(&data->ts_event_work, mcs5000_ts_irq_worker);
-
-	data->input_dev = input_allocate_device();
-	if (data->input_dev == NULL) {
-		ret = -ENOMEM;
-		goto err_input;
-	}
-
-	input_dev = data->input_dev;
-	input_dev->name = "MELPAS MCS-5000 Touchscreen";
-	input_dev->id.bustype = BUS_I2C;
-	input_dev->dev.parent = &data->client->dev;
-	set_bit(EV_ABS, input_dev->evbit);
-	set_bit(ABS_X, input_dev->absbit);
-	set_bit(ABS_Y, input_dev->absbit);
-	set_bit(EV_KEY, input_dev->evbit);
-	set_bit(BTN_TOUCH, input_dev->keybit);
-	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
-
-	ret = input_register_device(data->input_dev);
-	if (ret < 0)
-		goto err_register;
-
-	ret = request_irq(data->irq, mcs5000_ts_interrupt, IRQF_TRIGGER_LOW,
-			"mcs5000_ts_input", data);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to register interrupt\n");
-		goto err_irq;
-	}
-
-	input_set_drvdata(input_dev, data);
-
-	return 0;
-err_irq:
-	input_unregister_device(data->input_dev);
-	data->input_dev = NULL;
-err_register:
-	input_free_device(data->input_dev);
-err_input:
-	return ret;
+	disable_irq_nosync(irq);
+	return IRQ_WAKE_THREAD;
 }
 
 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
 {
+	const struct mcs5000_ts_platform_data *platform_data = data->platform_data;
 	struct i2c_client *client = data->client;
-	struct mcs5000_ts_platform_data *platform_data = data->platform_data;
 
 	/* Touch reset & sleep mode */
 	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
@@ -259,53 +196,69 @@ static int __devinit mcs5000_ts_probe(struct i2c_client *client,
 		const struct i2c_device_id *idp)
 {
 	struct mcs5000_ts_data *data;
-	int ret;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!client->dev.platform_data)
+		return -EINVAL;
 
 	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&client->dev, "Failed to allocate driver data\n");
-		ret = -ENOMEM;
-		goto exit;
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
 	}
 
 	data->client = client;
+	data->input_dev = input_dev;
 	data->platform_data = client->dev.platform_data;
-	data->irq = client->irq;
-	atomic_set(&data->irq_disable, 0);
 
-	i2c_set_clientdata(client, data);
+	input_dev->name = "MELPAS MCS-5000 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &data->client->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
 
-	if (data->platform_data && data->platform_data->set_pin)
+	input_set_drvdata(input_dev, data);
+
+	if (data->platform_data->set_pin)
 		data->platform_data->set_pin();
 
-	ret = mcs5000_ts_input_init(data);
-	if (ret)
-		goto exit_free;
+	error = request_threaded_irq(client->irq,
+				mcs5000_ts_hardirq, mcs5000_ts_interrupt,
+				IRQF_TRIGGER_LOW, "mcs5000_ts_input", data);
+	if (error < 0) {
+		dev_err(&data->client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(data->input_dev);
+	if (error < 0)
+		goto err_free_irq;
 
 	mcs5000_ts_phys_init(data);
+	i2c_set_clientdata(client, data);
 
 	return 0;
 
-exit_free:
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
 	kfree(data);
-	i2c_set_clientdata(client, NULL);
-exit:
-	return ret;
+	return error;
 }
 
 static int __devexit mcs5000_ts_remove(struct i2c_client *client)
 {
 	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 
-	free_irq(data->irq, data);
-	cancel_work_sync(&data->ts_event_work);
-
-	/*
-	 * If work indeed has been cancelled, disable_irq() will have been left
-	 * unbalanced from mcs5000_ts_interrupt().
-	 */
-	while (atomic_dec_return(&data->irq_disable) >= 0)
-		enable_irq(data->irq);
+	free_irq(client->irq, data);
 
 	input_unregister_device(data->input_dev);
 	kfree(data);
@@ -326,9 +279,8 @@ static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
 
 static int mcs5000_ts_resume(struct i2c_client *client)
 {
-	struct mcs5000_ts_data *data;
+	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 
-	data = i2c_get_clientdata(client);
 	mcs5000_ts_phys_init(data);
 
 	return 0;

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* RE: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-14  6:04 ` Dmitry Torokhov
@ 2009-07-14  6:47   ` Marek Szyprowski
  2009-07-14  7:26     ` Joonyoung Shim
  2009-07-15  7:51   ` Joonyoung Shim
  1 sibling, 1 reply; 9+ messages in thread
From: Marek Szyprowski @ 2009-07-14  6:47 UTC (permalink / raw)
  To: 'Dmitry Torokhov', 'Joonyoung Shim'
  Cc: linux-input, kyungmin.park, Tomasz Fujak, Marek Szyprowski

Hello,

On Tuesday, July 14, 2009 8:04 AM, Dmitry Torokhov wrote:

> Hi Joonyoung,
> 
> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
> > The MELPAS MCS-5000 is the touchscreen controller. The overview of this
> > controller can see at the following website:
> >
> > http://www.melfas.com/product/product01.asp?k_r=eng_
> >
> > This driver is tested on s3c6410 NCP board and supports only the i2c
> > interface.
> >
> > Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> > ---
> > Dear Dmitry,
> >
> > I sent the patch v2, but couldn't get any response.
> > This patch v3 is updated a little bit from v2.
> >
> 
> While I was sittign on the patch mainline acquired threaded IRQ support
> which fits the bill here and simplifies logic quite a bit, could you
> please try the patch below and tell me if the touchscreen still works?

I have no idea what I do wrong, but this patch also does not apply here:

$ git apply touchscreen-update.diff
error: patch failed: drivers/input/touchscreen/mcs5000_ts.c:259
error: drivers/input/touchscreen/mcs5000_ts.c: patch does not apply

$ patch -p1 < touchscreen-update.diff
patching file drivers/input/touchscreen/mcs5000_ts.c
Hunk #6 FAILED at 196.
1 out of 7 hunks FAILED -- saving rejects to file drivers/input/touchscreen/mcs5000_ts.c.rej

I've tried it on clean 'v3' patch posted in '[PATCH v3] Input: add
touchscreen driver for MELFAS MCS-5000 controller' mail on Friday 
2009-07-10 04:10.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-14  6:47   ` Marek Szyprowski
@ 2009-07-14  7:26     ` Joonyoung Shim
  0 siblings, 0 replies; 9+ messages in thread
From: Joonyoung Shim @ 2009-07-14  7:26 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: 'Dmitry Torokhov', linux-input, kyungmin.park, Tomasz Fujak

On 7/14/2009 3:47 PM, Marek Szyprowski wrote:
> Hello,
> 
> On Tuesday, July 14, 2009 8:04 AM, Dmitry Torokhov wrote:
> 
>> Hi Joonyoung,
>>
>> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
>>> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
>>> controller can see at the following website:
>>>
>>> http://www.melfas.com/product/product01.asp?k_r=eng_
>>>
>>> This driver is tested on s3c6410 NCP board and supports only the i2c
>>> interface.
>>>
>>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>>> ---
>>> Dear Dmitry,
>>>
>>> I sent the patch v2, but couldn't get any response.
>>> This patch v3 is updated a little bit from v2.
>>>
>> While I was sittign on the patch mainline acquired threaded IRQ support
>> which fits the bill here and simplifies logic quite a bit, could you
>> please try the patch below and tell me if the touchscreen still works?
> 
> I have no idea what I do wrong, but this patch also does not apply here:
> 
> $ git apply touchscreen-update.diff
> error: patch failed: drivers/input/touchscreen/mcs5000_ts.c:259
> error: drivers/input/touchscreen/mcs5000_ts.c: patch does not apply
> 
> $ patch -p1 < touchscreen-update.diff
> patching file drivers/input/touchscreen/mcs5000_ts.c
> Hunk #6 FAILED at 196.
> 1 out of 7 hunks FAILED -- saving rejects to file drivers/input/touchscreen/mcs5000_ts.c.rej

Hmm, I've tried '$ patch -p1' also, but i have no problem.

Marek,
This patch of Dmitry needs the latest kernel source, but our source 
doesn't seem latest, so i cannot compile.  Can you update to the latest
kernel?

> 
> I've tried it on clean 'v3' patch posted in '[PATCH v3] Input: add
> touchscreen driver for MELFAS MCS-5000 controller' mail on Friday 
> 2009-07-10 04:10.
> 
> Best regards
> --
> Marek Szyprowski
> Samsung Poland R&D Center
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-14  6:04 ` Dmitry Torokhov
  2009-07-14  6:47   ` Marek Szyprowski
@ 2009-07-15  7:51   ` Joonyoung Shim
  2009-07-15 15:30     ` Dmitry Torokhov
  1 sibling, 1 reply; 9+ messages in thread
From: Joonyoung Shim @ 2009-07-15  7:51 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

On 7/14/2009 3:04 PM, Dmitry Torokhov wrote:
> Hi Joonyoung,
> 
> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
>> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
>> controller can see at the following website:
>>
>> http://www.melfas.com/product/product01.asp?k_r=eng_
>>
>> This driver is tested on s3c6410 NCP board and supports only the i2c
>> interface.
>>
>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>> ---
>> Dear Dmitry,
>>
>> I sent the patch v2, but couldn't get any response.
>> This patch v3 is updated a little bit from v2.
>>
> 
> While I was sittign on the patch mainline acquired threaded IRQ support
> which fits the bill here and simplifies logic quite a bit, could you
> please try the patch below and tell me if the touchscreen still works?
> 

I've tested your patch, but it does not work. If i touch the pannel,
mcs5000_ts_hardirq is called once, but mcs5000_ts_interrupt is not
called, so the interrupt is not occurred any longer.

>> I have one question. The MCS-5000 controller don't support PRESSURE, so
>> i removed a fake PRESSURE report on driver, but tslib v1.0
>> (http://tslib.berlios.de) require the PRESSURE report from driver. I
>> wonder whether it is make sense to report a fake PRESSURE for tslib.
>>
> 
> I believe the adjustments to use BTN_TOUCH in absebse of ABS_PRESSURE
> has been applied to tslib, you need to talk to the maintainers about
> releasing updated version instead of adding fake events to the kernel.
> 

I see, thank you.

> Thanks.
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-15  7:51   ` Joonyoung Shim
@ 2009-07-15 15:30     ` Dmitry Torokhov
  2009-07-21  5:29       ` Joonyoung Shim
  0 siblings, 1 reply; 9+ messages in thread
From: Dmitry Torokhov @ 2009-07-15 15:30 UTC (permalink / raw)
  To: Joonyoung Shim; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

On Wed, Jul 15, 2009 at 04:51:15PM +0900, Joonyoung Shim wrote:
> On 7/14/2009 3:04 PM, Dmitry Torokhov wrote:
> > Hi Joonyoung,
> > 
> > On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
> >> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
> >> controller can see at the following website:
> >>
> >> http://www.melfas.com/product/product01.asp?k_r=eng_
> >>
> >> This driver is tested on s3c6410 NCP board and supports only the i2c
> >> interface.
> >>
> >> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> >> ---
> >> Dear Dmitry,
> >>
> >> I sent the patch v2, but couldn't get any response.
> >> This patch v3 is updated a little bit from v2.
> >>
> > 
> > While I was sittign on the patch mainline acquired threaded IRQ support
> > which fits the bill here and simplifies logic quite a bit, could you
> > please try the patch below and tell me if the touchscreen still works?
> > 
> 
> I've tested your patch, but it does not work. If i touch the pannel,
> mcs5000_ts_hardirq is called once, but mcs5000_ts_interrupt is not
> called, so the interrupt is not occurred any longer.
> 

Hmm, wierd... I guess since threaded IRQs are pretty new there could be
some issues there.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-15 15:30     ` Dmitry Torokhov
@ 2009-07-21  5:29       ` Joonyoung Shim
  2009-07-21  7:45         ` Dmitry Torokhov
  0 siblings, 1 reply; 9+ messages in thread
From: Joonyoung Shim @ 2009-07-21  5:29 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

On 7/16/2009 12:30 AM, Dmitry Torokhov wrote:
> On Wed, Jul 15, 2009 at 04:51:15PM +0900, Joonyoung Shim wrote:
>> On 7/14/2009 3:04 PM, Dmitry Torokhov wrote:
>>> Hi Joonyoung,
>>>
>>> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
>>>> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
>>>> controller can see at the following website:
>>>>
>>>> http://www.melfas.com/product/product01.asp?k_r=eng_
>>>>
>>>> This driver is tested on s3c6410 NCP board and supports only the i2c
>>>> interface.
>>>>
>>>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>>>> ---
>>>> Dear Dmitry,
>>>>
>>>> I sent the patch v2, but couldn't get any response.
>>>> This patch v3 is updated a little bit from v2.
>>>>
>>> While I was sittign on the patch mainline acquired threaded IRQ support
>>> which fits the bill here and simplifies logic quite a bit, could you
>>> please try the patch below and tell me if the touchscreen still works?
>>>
>> I've tested your patch, but it does not work. If i touch the pannel,
>> mcs5000_ts_hardirq is called once, but mcs5000_ts_interrupt is not
>> called, so the interrupt is not occurred any longer.
>>
> 
> Hmm, wierd... I guess since threaded IRQs are pretty new there could be
> some issues there.
> 

I wonder, are there drivers using the threaded IRQs at present?
I want to refer another driver but i can't find it.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-21  5:29       ` Joonyoung Shim
@ 2009-07-21  7:45         ` Dmitry Torokhov
  2009-07-21 12:15           ` Joonyoung Shim
  0 siblings, 1 reply; 9+ messages in thread
From: Dmitry Torokhov @ 2009-07-21  7:45 UTC (permalink / raw)
  To: Joonyoung Shim; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

On Tue, Jul 21, 2009 at 02:29:55PM +0900, Joonyoung Shim wrote:
> On 7/16/2009 12:30 AM, Dmitry Torokhov wrote:
> > On Wed, Jul 15, 2009 at 04:51:15PM +0900, Joonyoung Shim wrote:
> >> On 7/14/2009 3:04 PM, Dmitry Torokhov wrote:
> >>> Hi Joonyoung,
> >>>
> >>> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
> >>>> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
> >>>> controller can see at the following website:
> >>>>
> >>>> http://www.melfas.com/product/product01.asp?k_r=eng_
> >>>>
> >>>> This driver is tested on s3c6410 NCP board and supports only the i2c
> >>>> interface.
> >>>>
> >>>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
> >>>> ---
> >>>> Dear Dmitry,
> >>>>
> >>>> I sent the patch v2, but couldn't get any response.
> >>>> This patch v3 is updated a little bit from v2.
> >>>>
> >>> While I was sittign on the patch mainline acquired threaded IRQ support
> >>> which fits the bill here and simplifies logic quite a bit, could you
> >>> please try the patch below and tell me if the touchscreen still works?
> >>>
> >> I've tested your patch, but it does not work. If i touch the pannel,
> >> mcs5000_ts_hardirq is called once, but mcs5000_ts_interrupt is not
> >> called, so the interrupt is not occurred any longer.
> >>
> > 
> > Hmm, wierd... I guess since threaded IRQs are pretty new there could be
> > some issues there.
> > 
> 
> I wonder, are there drivers using the threaded IRQs at present?
> I want to refer another driver but i can't find it.

I have drivers/input/misc/dm355evm_keys.c in my tree.

Anyways, I reviewed the code again and the problem with both patches is
that we should not be disabling IRQ in the hard IRQ handler as it
inhibits running the thread, so we need to move disable_irq_nosync to be
the very first thing we do in the threaded handler.

Updated patch below; please give it a spin. If it works the MAX driver
will need the same adjustment.

-- 
Dmitry

Input: mcs5000_ts - use threaded IRQs

From: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Threaded IRQs are exactly what this driver needs since it communicates
with the device over I2C bus, which requires sleeping.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---

 drivers/input/touchscreen/mcs5000_ts.c |  163 +++++++++++---------------------
 1 files changed, 58 insertions(+), 105 deletions(-)


diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index d6c1a94..61778ad 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/irq.h>
-#include <linux/workqueue.h>
 
 /* Registers */
 #define MCS5000_TS_STATUS		0x00
@@ -105,28 +104,25 @@ enum mcs5000_ts_read_offset {
 struct mcs5000_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	struct work_struct ts_event_work;
-	struct mcs5000_ts_platform_data *platform_data;
-
-	unsigned int irq;
-	atomic_t irq_disable;
+	const struct mcs5000_ts_platform_data *platform_data;
 };
 
-static struct i2c_driver mcs5000_ts_driver;
-
-static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
+static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
 {
+	struct mcs5000_ts_data *data = dev_id;
 	struct i2c_client *client = data->client;
 	u8 buffer[READ_BLOCK_SIZE];
 	int err;
 	int x;
 	int y;
 
+	disable_irq_nosync(irq);
+
 	err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
 			READ_BLOCK_SIZE, buffer);
 	if (err < 0) {
 		dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
-		return;
+		goto out;
 	}
 
 	switch (buffer[READ_INPUT_INFO]) {
@@ -134,6 +130,7 @@ static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
 		input_report_key(data->input_dev, BTN_TOUCH, 0);
 		input_sync(data->input_dev);
 		break;
+
 	case INPUT_TYPE_SINGLE:
 		x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
 		y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
@@ -143,98 +140,39 @@ static void mcs5000_ts_input_read(struct mcs5000_ts_data *data)
 		input_report_abs(data->input_dev, ABS_Y, y);
 		input_sync(data->input_dev);
 		break;
+
 	case INPUT_TYPE_DUAL:
 		/* TODO */
 		break;
+
 	case INPUT_TYPE_PALM:
 		/* TODO */
 		break;
+
 	case INPUT_TYPE_PROXIMITY:
 		/* TODO */
 		break;
+
 	default:
 		dev_err(&client->dev, "Unknown ts input type %d\n",
 				buffer[READ_INPUT_INFO]);
 		break;
 	}
-}
-
-static void mcs5000_ts_irq_worker(struct work_struct *work)
-{
-	struct mcs5000_ts_data *data = container_of(work,
-			struct mcs5000_ts_data, ts_event_work);
-
-	mcs5000_ts_input_read(data);
-
-	atomic_dec(&data->irq_disable);
-	enable_irq(data->irq);
-}
-
-static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
-{
-	struct mcs5000_ts_data *data = dev_id;
-
-	if (!work_pending(&data->ts_event_work)) {
-		disable_irq_nosync(data->irq);
-		atomic_inc(&data->irq_disable);
-		schedule_work(&data->ts_event_work);
-	}
 
+ out:
+	enable_irq(irq);
 	return IRQ_HANDLED;
 }
 
-static int mcs5000_ts_input_init(struct mcs5000_ts_data *data)
+static irqreturn_t mcs5000_ts_hardirq(int irq, void *dev_id)
 {
-	struct input_dev *input_dev;
-	int ret = 0;
-
-	INIT_WORK(&data->ts_event_work, mcs5000_ts_irq_worker);
-
-	data->input_dev = input_allocate_device();
-	if (data->input_dev == NULL) {
-		ret = -ENOMEM;
-		goto err_input;
-	}
-
-	input_dev = data->input_dev;
-	input_dev->name = "MELPAS MCS-5000 Touchscreen";
-	input_dev->id.bustype = BUS_I2C;
-	input_dev->dev.parent = &data->client->dev;
-	set_bit(EV_ABS, input_dev->evbit);
-	set_bit(ABS_X, input_dev->absbit);
-	set_bit(ABS_Y, input_dev->absbit);
-	set_bit(EV_KEY, input_dev->evbit);
-	set_bit(BTN_TOUCH, input_dev->keybit);
-	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
-
-	ret = input_register_device(data->input_dev);
-	if (ret < 0)
-		goto err_register;
-
-	ret = request_irq(data->irq, mcs5000_ts_interrupt, IRQF_TRIGGER_LOW,
-			"mcs5000_ts_input", data);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to register interrupt\n");
-		goto err_irq;
-	}
-
-	input_set_drvdata(input_dev, data);
-
-	return 0;
-err_irq:
-	input_unregister_device(data->input_dev);
-	data->input_dev = NULL;
-err_register:
-	input_free_device(data->input_dev);
-err_input:
-	return ret;
+	return IRQ_WAKE_THREAD;
 }
 
 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
 {
+	const struct mcs5000_ts_platform_data *platform_data = data->platform_data;
 	struct i2c_client *client = data->client;
-	struct mcs5000_ts_platform_data *platform_data = data->platform_data;
 
 	/* Touch reset & sleep mode */
 	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
@@ -259,53 +197,69 @@ static int __devinit mcs5000_ts_probe(struct i2c_client *client,
 		const struct i2c_device_id *idp)
 {
 	struct mcs5000_ts_data *data;
-	int ret;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!client->dev.platform_data)
+		return -EINVAL;
 
 	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&client->dev, "Failed to allocate driver data\n");
-		ret = -ENOMEM;
-		goto exit;
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
 	}
 
 	data->client = client;
+	data->input_dev = input_dev;
 	data->platform_data = client->dev.platform_data;
-	data->irq = client->irq;
-	atomic_set(&data->irq_disable, 0);
 
-	i2c_set_clientdata(client, data);
+	input_dev->name = "MELPAS MCS-5000 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &data->client->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
+
+	input_set_drvdata(input_dev, data);
 
-	if (data->platform_data && data->platform_data->set_pin)
+	if (data->platform_data->set_pin)
 		data->platform_data->set_pin();
 
-	ret = mcs5000_ts_input_init(data);
-	if (ret)
-		goto exit_free;
+	error = request_threaded_irq(client->irq,
+				mcs5000_ts_hardirq, mcs5000_ts_interrupt,
+				IRQF_TRIGGER_LOW, "mcs5000_ts_input", data);
+	if (error < 0) {
+		dev_err(&data->client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(data->input_dev);
+	if (error < 0)
+		goto err_free_irq;
 
 	mcs5000_ts_phys_init(data);
+	i2c_set_clientdata(client, data);
 
 	return 0;
 
-exit_free:
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
 	kfree(data);
-	i2c_set_clientdata(client, NULL);
-exit:
-	return ret;
+	return error;
 }
 
 static int __devexit mcs5000_ts_remove(struct i2c_client *client)
 {
 	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 
-	free_irq(data->irq, data);
-	cancel_work_sync(&data->ts_event_work);
-
-	/*
-	 * If work indeed has been cancelled, disable_irq() will have been left
-	 * unbalanced from mcs5000_ts_interrupt().
-	 */
-	while (atomic_dec_return(&data->irq_disable) >= 0)
-		enable_irq(data->irq);
+	free_irq(client->irq, data);
 
 	input_unregister_device(data->input_dev);
 	kfree(data);
@@ -326,9 +280,8 @@ static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
 
 static int mcs5000_ts_resume(struct i2c_client *client)
 {
-	struct mcs5000_ts_data *data;
+	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 
-	data = i2c_get_clientdata(client);
 	mcs5000_ts_phys_init(data);
 
 	return 0;

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller
  2009-07-21  7:45         ` Dmitry Torokhov
@ 2009-07-21 12:15           ` Joonyoung Shim
  0 siblings, 0 replies; 9+ messages in thread
From: Joonyoung Shim @ 2009-07-21 12:15 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, kyungmin.park, m.szyprowski, t.fujak

On 7/21/2009 4:45 PM, Dmitry Torokhov wrote:
> On Tue, Jul 21, 2009 at 02:29:55PM +0900, Joonyoung Shim wrote:
>> On 7/16/2009 12:30 AM, Dmitry Torokhov wrote:
>>> On Wed, Jul 15, 2009 at 04:51:15PM +0900, Joonyoung Shim wrote:
>>>> On 7/14/2009 3:04 PM, Dmitry Torokhov wrote:
>>>>> Hi Joonyoung,
>>>>>
>>>>> On Fri, Jul 10, 2009 at 11:10:12AM +0900, Joonyoung Shim wrote:
>>>>>> The MELPAS MCS-5000 is the touchscreen controller. The overview of this
>>>>>> controller can see at the following website:
>>>>>>
>>>>>> http://www.melfas.com/product/product01.asp?k_r=eng_
>>>>>>
>>>>>> This driver is tested on s3c6410 NCP board and supports only the i2c
>>>>>> interface.
>>>>>>
>>>>>> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
>>>>>> ---
>>>>>> Dear Dmitry,
>>>>>>
>>>>>> I sent the patch v2, but couldn't get any response.
>>>>>> This patch v3 is updated a little bit from v2.
>>>>>>
>>>>> While I was sittign on the patch mainline acquired threaded IRQ support
>>>>> which fits the bill here and simplifies logic quite a bit, could you
>>>>> please try the patch below and tell me if the touchscreen still works?
>>>>>
>>>> I've tested your patch, but it does not work. If i touch the pannel,
>>>> mcs5000_ts_hardirq is called once, but mcs5000_ts_interrupt is not
>>>> called, so the interrupt is not occurred any longer.
>>>>
>>> Hmm, wierd... I guess since threaded IRQs are pretty new there could be
>>> some issues there.
>>>
>> I wonder, are there drivers using the threaded IRQs at present?
>> I want to refer another driver but i can't find it.
> 
> I have drivers/input/misc/dm355evm_keys.c in my tree.

I found it.

> 
> Anyways, I reviewed the code again and the problem with both patches is
> that we should not be disabling IRQ in the hard IRQ handler as it
> inhibits running the thread, so we need to move disable_irq_nosync to be
> the very first thing we do in the threaded handler.
> 

This has one problem.

The MCS5000 detects interrupt at low level. After interrupt occurs, the 
interrupt signal of the MCS5000 maintains the low level. It needs an i2c
operation to change to high the interrupt signal.

If we do disbling IRQ in the threaded handler instead of the hard IRQ
handler, the interrupt occurs infinitely because the interrupt signal is
low.

I have tested your new patch, and it appeared above result. It will 
maybe need a dummy i2c operation in the hard IRQ handler, but the i2c
operation cannot use in the IRQ handler.

> Updated patch below; please give it a spin. If it works the MAX driver
> will need the same adjustment.
> 

I'm not sure about the MAX7359 keypad driver, but I think we need some
thing disabling IRQ in hard IRQ handler to change to driver using
threaded irq.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-07-21 12:15 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-07-10  2:10 [PATCH v3] Input: add touchscreen driver for MELFAS MCS-5000 controller Joonyoung Shim
2009-07-14  6:04 ` Dmitry Torokhov
2009-07-14  6:47   ` Marek Szyprowski
2009-07-14  7:26     ` Joonyoung Shim
2009-07-15  7:51   ` Joonyoung Shim
2009-07-15 15:30     ` Dmitry Torokhov
2009-07-21  5:29       ` Joonyoung Shim
2009-07-21  7:45         ` Dmitry Torokhov
2009-07-21 12:15           ` Joonyoung Shim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.