* [PATCH v3] input: add driver for pixcir i2c touchscreens
@ 2011-05-24 3:25 jcbian
2011-07-04 16:50 ` Dmitry Torokhov
2011-07-04 20:49 ` Henrik Rydberg
0 siblings, 2 replies; 8+ messages in thread
From: jcbian @ 2011-05-24 3:25 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, dqmeng, zlchen
Hi all,
This patch adds a driver for PIXCIR's I2C connected touchscreens.
Request the IRQ by doing request_threaded_irq() as v3.
Signed-off-by: Jianchun <jcbian@pixcir.com.cn>
---
drivers/input/touchscreen/Kconfig | 12 ++
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/pixcir_i2c_ts.c | 269
+++++++++++++++++++++++++++++
drivers/input/touchscreen/pixcir_i2c_ts.h | 13 ++
4 files changed, 295 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/pixcir_i2c_ts.c
create mode 100644 drivers/input/touchscreen/pixcir_i2c_ts.h
diff --git a/drivers/input/touchscreen/Kconfig
b/drivers/input/touchscreen/Kconfig
index 434fd80..e91f40f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -714,4 +714,16 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
+config TOUCHSCREEN_PIXCIR
+ tristate "PIXCIR I2C touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a pixcir i2c touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pixcir_i2c_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile
b/drivers/input/touchscreen/Makefile
index ca94098..585c0f0 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c
b/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 0000000..b734813
--- /dev/null
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -0,0 +1,269 @@
+/* drivers/input/touchscreen/pixcir_i2c_ts.c
+ *
+ * Copyright (C) 2010-2011 Pixcir, Inc.
+ * V1.0
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include "pixcir_i2c_ts.h"
+
+struct pixcir_i2c_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ wait_queue_head_t wait;
+ const struct pixcir_i2c_ts_platform *chip;
+ unsigned int attb_pin;
+ int irq;
+};
+
+static int pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+{
+ struct pixcir_i2c_ts_data *tsdata = data;
+
+ u8 touching, oldtouching;
+ u16 posx1, posy1, posx2, posy2;
+ u8 rdbuf[10], wrbuf[1];
+ int ret;
+
+ memset(wrbuf, 0, sizeof(wrbuf));
+ memset(rdbuf, 0, sizeof(rdbuf));
+
+ wrbuf[0] = 0;
+ ret = i2c_master_send(tsdata->client, wrbuf, 1);
+ if (ret != 1) {
+ dev_err(&tsdata->client->dev, "Unable to write to i2c touchscreen!\n");
+ goto out;
+ }
+
+ ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+ if (ret != sizeof(rdbuf)) {
+ dev_err(&tsdata->client->dev, "Unable to read i2c page!\n");
+ goto out;
+ }
+
+ touching = rdbuf[0];
+ oldtouching = rdbuf[1];
+ posx1 = ((rdbuf[3] << 8) | rdbuf[2]);
+ posy1 = ((rdbuf[5] << 8) | rdbuf[4]);
+ posx2 = ((rdbuf[7] << 8) | rdbuf[6]);
+ posy2 = ((rdbuf[9] << 8) | rdbuf[8]);
+
+ input_report_key(tsdata->input, BTN_TOUCH, touching);
+
+ if (touching == 1) {
+ input_report_abs(tsdata->input, ABS_X, posx1);
+ input_report_abs(tsdata->input, ABS_Y, posy1);
+ }
+
+ if (touching == 2) {
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
+ input_mt_sync(tsdata->input);
+
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx2);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy2);
+ input_mt_sync(tsdata->input);
+ } else
+ input_mt_sync(tsdata->input);
+ input_sync(tsdata->input);
+
+ return 0;
+
+out:
+ return -EINVAL;
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+ do {
+ pixcir_ts_poscheck(tsdata);
+ tsdata->attb_pin = tsdata->chip->attb_read_val();
+ if (tsdata->attb_pin == ATTB_PIN_LOW)
+ wait_event_timeout(tsdata->wait, TRUE,
+ msecs_to_jiffies(20));
+ } while (!tsdata->attb_pin);
+
+ return IRQ_HANDLED;
+}
+
+static void pixcir_ts_close(struct input_dev *dev)
+{
+
+}
+
+static int pixcir_i2c_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pixcir_i2c_ts_data *tsdata;
+ struct input_dev *input;
+ const struct pixcir_i2c_ts_platform *pdata =
+ client->dev.platform_data;
+ int error;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ if (!tsdata) {
+ dev_err(&client->dev, "Failed to allocate driver data!\n");
+ error = -ENOMEM;
+ dev_set_drvdata(&client->dev, NULL);
+ return error;
+ }
+
+ dev_set_drvdata(&client->dev, tsdata);
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(&client->dev, "Failed to allocate input device!\n");
+ error = -ENOMEM;
+ input_free_device(input);
+ kfree(tsdata);
+ }
+
+ init_waitqueue_head(&tsdata->wait);
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &client->dev;
+
+ input->close = pixcir_ts_close;
+
+ input_set_drvdata(input, tsdata);
+
+ tsdata->client = client;
+ tsdata->input = input;
+ tsdata->chip = pdata;
+ tsdata->irq = client->irq;
+
+ set_bit(EV_SYN, input->evbit);
+ set_bit(EV_KEY, input->evbit);
+ set_bit(EV_ABS, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
+ input_set_abs_params(input, ABS_X, 0, pdata->ts_x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, pdata->ts_y_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->ts_x_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->ts_y_max, 0, 0);
+
+ if (input_register_device(input)) {
+ input_free_device(input);
+ kfree(tsdata);
+ }
+
+ if (request_threaded_irq(tsdata->irq, NULL, pixcir_ts_isr,
+ IRQF_TRIGGER_FALLING, client->name, tsdata)) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ input_unregister_device(input);
+ input = NULL;
+ }
+
+ device_init_wakeup(&client->dev, 1);
+
+ return 0;
+}
+
+static int pixcir_i2c_ts_remove(struct i2c_client *client)
+{
+ struct pixcir_i2c_ts_data *tsdata;
+
+ tsdata = i2c_get_clientdata(client);
+ wake_up(&tsdata->wait);
+ free_irq(tsdata->irq, tsdata);
+ input_unregister_device(tsdata->input);
+ kfree(tsdata);
+ dev_set_drvdata(&client->dev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pixcir_i2c_ts_suspend(struct i2c_client *client,
pm_message_t mesg)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_get_drvdata(&client->dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(tsdata->irq);
+
+ return 0;
+}
+
+static int pixcir_i2c_ts_resume(struct i2c_client *client)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_get_drvdata(&client->dev);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(tsdata->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops pixcir_dev_pm_ops = {
+ .suspend = pixcir_i2c_ts_suspend,
+ .resume = pixcir_i2c_ts_resume,
+};
+
+#else
+#define pixcir_i2c_ts_suspend NULL
+#define pixcir_i2c_ts_resume NULL
+#endif
+
+static const struct i2c_device_id pixcir_i2c_ts_id[] = {
+ { "pixcir_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+
+static struct i2c_driver pixcir_i2c_ts_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pixcir_ts",
+#ifdef PM_CONFIG
+ .pm = &pixcir_dev_pm_ops,
+#endif
+ },
+ .probe = pixcir_i2c_ts_probe,
+ .remove = pixcir_i2c_ts_remove,
+ .id_table = pixcir_i2c_ts_id,
+};
+
+static int __init pixcir_i2c_ts_init(void)
+{
+ /*pixcir_wq = create_singlethread_workqueue("pixcir_wq");
+ if (!pixcir_wq)
+ return -ENOMEM;*/
+ return i2c_add_driver(&pixcir_i2c_ts_driver);
+}
+
+static void __exit pixcir_i2c_ts_exit(void)
+{
+ i2c_del_driver(&pixcir_i2c_ts_driver);
+ /*if (pixcir_wq)
+ destroy_workqueue(pixcir_wq);*/
+}
+
+MODULE_AUTHOR("Jianchun Bian<jcbian@pixcir.com.cn>,Dequan
Meng<dqmeng@pixcir.com.cn>");
+MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
+
+module_init(pixcir_i2c_ts_init);
+module_exit(pixcir_i2c_ts_exit);
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.h
b/drivers/input/touchscreen/pixcir_i2c_ts.h
new file mode 100644
index 0000000..b037c27
--- /dev/null
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.h
@@ -0,0 +1,13 @@
+#ifndef _PIXCIR_I2C_TS_H
+#define _PIXCIR_I2C_TS_H
+
+#define TRUE 1
+#define ATTB_PIN_LOW 0
+
+struct pixcir_i2c_ts_platform {
+ int (*attb_read_val) (void);
+ int ts_x_max;
+ int ts_y_max;
+};
+
+#endif
--
1.7.0.4
--
Best Regards
Bee/Pixcir
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-05-24 3:25 [PATCH v3] input: add driver for pixcir i2c touchscreens jcbian
@ 2011-07-04 16:50 ` Dmitry Torokhov
2011-07-05 19:30 ` Henrik Rydberg
2011-07-04 20:49 ` Henrik Rydberg
1 sibling, 1 reply; 8+ messages in thread
From: Dmitry Torokhov @ 2011-07-04 16:50 UTC (permalink / raw)
To: jcbian; +Cc: linux-input, dqmeng, zlchen
Hi Jianchun,
On Tue, May 24, 2011 at 11:25:10AM +0800, jcbian wrote:
> +
> +static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
> +{
> + struct pixcir_i2c_ts_data *tsdata = dev_id;
> +
> + do {
> + pixcir_ts_poscheck(tsdata);
> + tsdata->attb_pin = tsdata->chip->attb_read_val();
> + if (tsdata->attb_pin == ATTB_PIN_LOW)
> + wait_event_timeout(tsdata->wait, TRUE,
> + msecs_to_jiffies(20));
This doews not mak sense, you do not do any waiting here since your
condition is 'TRUE' and this the thread never sleeps but spins
constantly.
You also ignored my other comments...
Does the patch below still work for you?
Thanks.
--
Dmitry
Input: add driver for pixcir i2c touchscreens
From: Jianchun Bian <jcbian@pixcir.com.cn>
This patch adds a driver for PIXCIR's I2C connected touchscreens.
Signed-off-by: Jianchun <jcbian@pixcir.com.cn>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1
drivers/input/touchscreen/pixcir_i2c_ts.c | 235 +++++++++++++++++++++++++++++
include/linux/input/pixcir_ts.h | 10 +
4 files changed, 258 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/pixcir_i2c_ts.c
create mode 100644 include/linux/input/pixcir_ts.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index a369c94..358be1f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -464,6 +464,18 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
+config TOUCHSCREEN_PIXCIR
+ tristate "PIXCIR I2C touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a pixcir i2c touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pixcir_i2c_ts.
+
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 141ee3e..c0727a4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 0000000..0c1ae91
--- /dev/null
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -0,0 +1,235 @@
+/*
+ * Driver for Pixcir I2C touchscreen controllers.
+ *
+ * Copyright (C) 2010-2011 Pixcir, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/pixcir_ts.h>
+
+struct pixcir_i2c_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ const struct pixcir_ts_platform_data *chip;
+ bool exiting;
+};
+
+static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+{
+ struct pixcir_i2c_ts_data *tsdata = data;
+
+ u8 touching;
+ u16 posx1, posy1, posx2, posy2;
+ u8 rdbuf[10], wrbuf[1] = { 0 };
+ int ret;
+
+ ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+ if (ret != sizeof(wrbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_send failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+ if (ret != sizeof(rdbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_recv failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ touching = rdbuf[0];
+ posx1 = (rdbuf[3] << 8) | rdbuf[2];
+ posy1 = (rdbuf[5] << 8) | rdbuf[4];
+ posx2 = (rdbuf[7] << 8) | rdbuf[6];
+ posy2 = (rdbuf[9] << 8) | rdbuf[8];
+
+ input_report_key(tsdata->input, BTN_TOUCH, touching);
+ input_report_abs(tsdata->input, ABS_X, posx1);
+ input_report_abs(tsdata->input, ABS_Y, posy1);
+
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
+ input_mt_sync(tsdata->input);
+
+ if (touching == 2) {
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx2);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy2);
+ input_mt_sync(tsdata->input);
+ }
+
+ input_sync(tsdata->input);
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+ while (!tsdata->exiting) {
+ pixcir_ts_poscheck(tsdata);
+
+ if (tsdata->chip->attb_read_val())
+ break;
+
+ msleep(20);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pixcir_i2c_ts_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int pixcir_i2c_ts_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+ pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+
+static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
+ struct pixcir_i2c_ts_data *tsdata;
+ struct input_dev *input;
+ int error;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsdata || !input) {
+ dev_err(&client->dev, "Failed to allocate driver data!\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsdata->client = client;
+ tsdata->input = input;
+ tsdata->chip = pdata;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &client->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
+
+ input_set_drvdata(input, tsdata);
+
+ error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
+ IRQF_TRIGGER_FALLING,
+ client->name, tsdata);
+ if (error) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, tsdata);
+ device_init_wakeup(&client->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, tsdata);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsdata);
+ return error;
+}
+
+static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
+{
+ struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
+
+ device_init_wakeup(&client->dev, 0);
+
+ tsdata->exiting = true;
+ mb();
+ free_irq(client->irq, tsdata);
+
+ input_unregister_device(tsdata->input);
+ kfree(tsdata);
+
+ return 0;
+}
+
+static const struct i2c_device_id pixcir_i2c_ts_id[] = {
+ { "pixcir_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+
+static struct i2c_driver pixcir_i2c_ts_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pixcir_ts",
+ .pm = &pixcir_dev_pm_ops,
+ },
+ .probe = pixcir_i2c_ts_probe,
+ .remove = __devexit_p(pixcir_i2c_ts_remove),
+ .id_table = pixcir_i2c_ts_id,
+};
+
+static int __init pixcir_i2c_ts_init(void)
+{
+ return i2c_add_driver(&pixcir_i2c_ts_driver);
+}
+module_init(pixcir_i2c_ts_init);
+
+static void __exit pixcir_i2c_ts_exit(void)
+{
+ i2c_del_driver(&pixcir_i2c_ts_driver);
+}
+module_exit(pixcir_i2c_ts_exit);
+
+MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
+MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
new file mode 100644
index 0000000..7163d91
--- /dev/null
+++ b/include/linux/input/pixcir_ts.h
@@ -0,0 +1,10 @@
+#ifndef _PIXCIR_I2C_TS_H
+#define _PIXCIR_I2C_TS_H
+
+struct pixcir_ts_platform_data {
+ int (*attb_read_val)(void);
+ int x_max;
+ int y_max;
+};
+
+#endif
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-05-24 3:25 [PATCH v3] input: add driver for pixcir i2c touchscreens jcbian
2011-07-04 16:50 ` Dmitry Torokhov
@ 2011-07-04 20:49 ` Henrik Rydberg
1 sibling, 0 replies; 8+ messages in thread
From: Henrik Rydberg @ 2011-07-04 20:49 UTC (permalink / raw)
To: jcbian; +Cc: dmitry.torokhov, linux-input, dqmeng, zlchen
Hi jcbian,
> This patch adds a driver for PIXCIR's I2C connected touchscreens.
> Request the IRQ by doing request_threaded_irq() as v3.
Some MT comments below.
> +static int pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
Perhaps it is possible to find a more descriptive name?
> +{
> + struct pixcir_i2c_ts_data *tsdata = data;
> +
> + u8 touching, oldtouching;
> + u16 posx1, posy1, posx2, posy2;
> + u8 rdbuf[10], wrbuf[1];
> + int ret;
> +
> + memset(wrbuf, 0, sizeof(wrbuf));
> + memset(rdbuf, 0, sizeof(rdbuf));
> +
> + wrbuf[0] = 0;
> + ret = i2c_master_send(tsdata->client, wrbuf, 1);
> + if (ret != 1) {
> + dev_err(&tsdata->client->dev, "Unable to write to i2c touchscreen!\n");
> + goto out;
> + }
How about returning the error code here directly instead?
> +
> + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> + if (ret != sizeof(rdbuf)) {
> + dev_err(&tsdata->client->dev, "Unable to read i2c page!\n");
> + goto out;
> + }
Ditto.
> +
> + touching = rdbuf[0];
> + oldtouching = rdbuf[1];
Is oldtouching ever used?
> + posx1 = ((rdbuf[3] << 8) | rdbuf[2]);
> + posy1 = ((rdbuf[5] << 8) | rdbuf[4]);
> + posx2 = ((rdbuf[7] << 8) | rdbuf[6]);
> + posy2 = ((rdbuf[9] << 8) | rdbuf[8]);
> +
> + input_report_key(tsdata->input, BTN_TOUCH, touching);
> +
> + if (touching == 1) {
> + input_report_abs(tsdata->input, ABS_X, posx1);
> + input_report_abs(tsdata->input, ABS_Y, posy1);
> + }
No MT data for one finger?
> +
> + if (touching == 2) {
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
> + input_mt_sync(tsdata->input);
> +
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx2);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy2);
> + input_mt_sync(tsdata->input);
> + } else
> + input_mt_sync(tsdata->input);
input_mt_sync() is always called, please simplify.
> + input_sync(tsdata->input);
> +
> + return 0;
> +
> +out:
> + return -EINVAL;
> +}
> +
[...]
> +static int pixcir_i2c_ts_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct pixcir_i2c_ts_data *tsdata;
> + struct input_dev *input;
> + const struct pixcir_i2c_ts_platform *pdata =
> + client->dev.platform_data;
> + int error;
> +
> + if (!pdata) {
> + dev_err(&client->dev, "platform data not defined\n");
> + return -EINVAL;
> + }
> +
> + tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
> + if (!tsdata) {
> + dev_err(&client->dev, "Failed to allocate driver data!\n");
> + error = -ENOMEM;
> + dev_set_drvdata(&client->dev, NULL);
> + return error;
> + }
> +
> + dev_set_drvdata(&client->dev, tsdata);
> +
> + input = input_allocate_device();
> + if (!input) {
> + dev_err(&client->dev, "Failed to allocate input device!\n");
> + error = -ENOMEM;
> + input_free_device(input);
> + kfree(tsdata);
> + }
> +
> + init_waitqueue_head(&tsdata->wait);
> +
> + input->name = client->name;
> + input->id.bustype = BUS_I2C;
> + input->dev.parent = &client->dev;
> +
> + input->close = pixcir_ts_close;
> +
> + input_set_drvdata(input, tsdata);
> +
> + tsdata->client = client;
> + tsdata->input = input;
> + tsdata->chip = pdata;
> + tsdata->irq = client->irq;
> +
> + set_bit(EV_SYN, input->evbit);
> + set_bit(EV_KEY, input->evbit);
> + set_bit(EV_ABS, input->evbit);
> + set_bit(BTN_TOUCH, input->keybit);
> + input_set_abs_params(input, ABS_X, 0, pdata->ts_x_max, 0, 0);
> + input_set_abs_params(input, ABS_Y, 0, pdata->ts_y_max, 0, 0);
> + input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->ts_x_max, 0, 0);
> + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->ts_y_max, 0, 0);
Is the device not capable of finger tracking? If not, it might be time
to turn finger tracking on in the input core. It is preferrable to use
protocol B these days.
> +
> + if (input_register_device(input)) {
> + input_free_device(input);
> + kfree(tsdata);
> + }
> +
> + if (request_threaded_irq(tsdata->irq, NULL, pixcir_ts_isr,
> + IRQF_TRIGGER_FALLING, client->name, tsdata)) {
> + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
> + input_unregister_device(input);
> + input = NULL;
> + }
> +
> + device_init_wakeup(&client->dev, 1);
> +
> + return 0;
> +}
Thanks,
Henrik
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-07-04 16:50 ` Dmitry Torokhov
@ 2011-07-05 19:30 ` Henrik Rydberg
2011-07-09 20:12 ` Dmitry Torokhov
2011-07-14 2:21 ` jcbian
0 siblings, 2 replies; 8+ messages in thread
From: Henrik Rydberg @ 2011-07-05 19:30 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: jcbian, linux-input, dqmeng, zlchen
Hi Dmitry,
> +static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +{
> + struct pixcir_i2c_ts_data *tsdata = data;
> +
> + u8 touching;
> + u16 posx1, posy1, posx2, posy2;
> + u8 rdbuf[10], wrbuf[1] = { 0 };
> + int ret;
> +
> + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
> + if (ret != sizeof(wrbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_send failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> + if (ret != sizeof(rdbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_recv failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + touching = rdbuf[0];
> + posx1 = (rdbuf[3] << 8) | rdbuf[2];
> + posy1 = (rdbuf[5] << 8) | rdbuf[4];
> + posx2 = (rdbuf[7] << 8) | rdbuf[6];
> + posy2 = (rdbuf[9] << 8) | rdbuf[8];
> +
> + input_report_key(tsdata->input, BTN_TOUCH, touching);
> + input_report_abs(tsdata->input, ABS_X, posx1);
> + input_report_abs(tsdata->input, ABS_Y, posy1);
> +
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
> + input_mt_sync(tsdata->input);
> +
> + if (touching == 2) {
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx2);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy2);
> + input_mt_sync(tsdata->input);
> + }
> +
> + input_sync(tsdata->input);
> +}
If the above function handles zero fingers as well, the MT finger
count comes out wrong in that case.
Cheers,
Henrik
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-07-05 19:30 ` Henrik Rydberg
@ 2011-07-09 20:12 ` Dmitry Torokhov
2011-07-23 18:18 ` Henrik Rydberg
2011-07-14 2:21 ` jcbian
1 sibling, 1 reply; 8+ messages in thread
From: Dmitry Torokhov @ 2011-07-09 20:12 UTC (permalink / raw)
To: Henrik Rydberg; +Cc: jcbian, linux-input, dqmeng, zlchen
On Tue, Jul 05, 2011 at 09:30:20PM +0200, Henrik Rydberg wrote:
>
> If the above function handles zero fingers as well, the MT finger
> count comes out wrong in that case.
>
Hmm, indeed. How about the patch below instead?
Thanks.
--
Dmitry
Input: add driver for pixcir i2c touchscreens
From: Jianchun Bian <jcbian@pixcir.com.cn>
This patch adds a driver for PIXCIR's I2C connected touchscreens.
Signed-off-by: Jianchun <jcbian@pixcir.com.cn>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1
drivers/input/touchscreen/pixcir_i2c_ts.c | 242 +++++++++++++++++++++++++++++
include/linux/input/pixcir_ts.h | 10 +
4 files changed, 265 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/pixcir_i2c_ts.c
create mode 100644 include/linux/input/pixcir_ts.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index a369c94..358be1f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -464,6 +464,18 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
+config TOUCHSCREEN_PIXCIR
+ tristate "PIXCIR I2C touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a pixcir i2c touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pixcir_i2c_ts.
+
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 141ee3e..c0727a4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 0000000..80067b2
--- /dev/null
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -0,0 +1,242 @@
+/*
+ * Driver for Pixcir I2C touchscreen controllers.
+ *
+ * Copyright (C) 2010-2011 Pixcir, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/pixcir_ts.h>
+
+struct pixcir_i2c_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ const struct pixcir_ts_platform_data *chip;
+ bool exiting;
+};
+
+static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+{
+ struct pixcir_i2c_ts_data *tsdata = data;
+ u8 rdbuf[10], wrbuf[1] = { 0 };
+ u8 touch, old_touch;
+ int ret;
+
+ ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+ if (ret != sizeof(wrbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_send failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+ if (ret != sizeof(rdbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_recv failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ touch = rdbuf[0];
+ old_touch = rdbuf[1];
+ if (touch) {
+ u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
+ u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
+ u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
+ u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
+
+ input_report_key(tsdata->input, BTN_TOUCH, 1);
+ input_report_abs(tsdata->input, ABS_X, posx1);
+ input_report_abs(tsdata->input, ABS_Y, posy1);
+
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
+ input_mt_sync(tsdata->input);
+
+ if (touch == 2) {
+ input_report_abs(tsdata->input,
+ ABS_MT_POSITION_X, posx2);
+ input_report_abs(tsdata->input,
+ ABS_MT_POSITION_Y, posy2);
+ input_mt_sync(tsdata->input);
+ }
+ } else {
+ input_report_key(tsdata->input, BTN_TOUCH, 0);
+ if (old_touch)
+ input_mt_sync(tsdata->input);
+ }
+
+ input_sync(tsdata->input);
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+ while (!tsdata->exiting) {
+ pixcir_ts_poscheck(tsdata);
+
+ if (tsdata->chip->attb_read_val())
+ break;
+
+ msleep(20);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pixcir_i2c_ts_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int pixcir_i2c_ts_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+ pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+
+static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
+ struct pixcir_i2c_ts_data *tsdata;
+ struct input_dev *input;
+ int error;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsdata || !input) {
+ dev_err(&client->dev, "Failed to allocate driver data!\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsdata->client = client;
+ tsdata->input = input;
+ tsdata->chip = pdata;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &client->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
+
+ input_set_drvdata(input, tsdata);
+
+ error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
+ IRQF_TRIGGER_FALLING,
+ client->name, tsdata);
+ if (error) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, tsdata);
+ device_init_wakeup(&client->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, tsdata);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsdata);
+ return error;
+}
+
+static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
+{
+ struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
+
+ device_init_wakeup(&client->dev, 0);
+
+ tsdata->exiting = true;
+ mb();
+ free_irq(client->irq, tsdata);
+
+ input_unregister_device(tsdata->input);
+ kfree(tsdata);
+
+ return 0;
+}
+
+static const struct i2c_device_id pixcir_i2c_ts_id[] = {
+ { "pixcir_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+
+static struct i2c_driver pixcir_i2c_ts_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pixcir_ts",
+ .pm = &pixcir_dev_pm_ops,
+ },
+ .probe = pixcir_i2c_ts_probe,
+ .remove = __devexit_p(pixcir_i2c_ts_remove),
+ .id_table = pixcir_i2c_ts_id,
+};
+
+static int __init pixcir_i2c_ts_init(void)
+{
+ return i2c_add_driver(&pixcir_i2c_ts_driver);
+}
+module_init(pixcir_i2c_ts_init);
+
+static void __exit pixcir_i2c_ts_exit(void)
+{
+ i2c_del_driver(&pixcir_i2c_ts_driver);
+}
+module_exit(pixcir_i2c_ts_exit);
+
+MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
+MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
new file mode 100644
index 0000000..7163d91
--- /dev/null
+++ b/include/linux/input/pixcir_ts.h
@@ -0,0 +1,10 @@
+#ifndef _PIXCIR_I2C_TS_H
+#define _PIXCIR_I2C_TS_H
+
+struct pixcir_ts_platform_data {
+ int (*attb_read_val)(void);
+ int x_max;
+ int y_max;
+};
+
+#endif
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-07-05 19:30 ` Henrik Rydberg
2011-07-09 20:12 ` Dmitry Torokhov
@ 2011-07-14 2:21 ` jcbian
2011-07-23 18:24 ` Henrik Rydberg
1 sibling, 1 reply; 8+ messages in thread
From: jcbian @ 2011-07-14 2:21 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Henrik Rydberg, linux-input, dqmeng, zlchen
Hi Dmitry & Henrik,
Thanks for your suggestions and modification .I have test it and it works well.
Indeed,I think the old_touch is not needed,the follow
+ if (old_touch)
+ input_mt_sync(tsdata->input);
could be removed. So,How about below?
Thanks.
--
Jcbian
Input: add driver for pixcir i2c touchscreens
From: Jianchun Bian <jcbian@pixcir.com.cn>
This patch adds a driver for PIXCIR's I2C connected touchscreens.
Signed-off-by: Jianchun <jcbian@pixcir.com.cn>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1
drivers/input/touchscreen/pixcir_i2c_ts.c | 242 +++++++++++++++++++++++++++++
include/linux/input/pixcir_ts.h | 10 +
4 files changed, 265 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/pixcir_i2c_ts.c
create mode 100644 include/linux/input/pixcir_ts.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index a369c94..358be1f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -464,6 +464,18 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
+config TOUCHSCREEN_PIXCIR
+ tristate "PIXCIR I2C touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a pixcir i2c touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pixcir_i2c_ts.
+
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 141ee3e..c0727a4 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 0000000..80067b2
--- /dev/null
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -0,0 +1,242 @@
+/*
+ * Driver for Pixcir I2C touchscreen controllers.
+ *
+ * Copyright (C) 2010-2011 Pixcir, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/pixcir_ts.h>
+
+struct pixcir_i2c_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ const struct pixcir_ts_platform_data *chip;
+ bool exiting;
+};
+
+static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+{
+ struct pixcir_i2c_ts_data *tsdata = data;
+ u8 rdbuf[10], wrbuf[1] = { 0 };
+ u8 touch, old_touch;
+ int ret;
+
+ ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+ if (ret != sizeof(wrbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_send failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+ if (ret != sizeof(rdbuf)) {
+ dev_err(&tsdata->client->dev,
+ "%s: i2c_master_recv failed(), ret=%d\n",
+ __func__, ret);
+ return;
+ }
+
+ touch = rdbuf[0];
+ old_touch = rdbuf[1];
+ if (touch) {
+ u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
+ u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
+ u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
+ u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
+
+ input_report_key(tsdata->input, BTN_TOUCH, 1);
+ input_report_abs(tsdata->input, ABS_X, posx1);
+ input_report_abs(tsdata->input, ABS_Y, posy1);
+
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
+ input_mt_sync(tsdata->input);
+
+ if (touch == 2) {
+ input_report_abs(tsdata->input,
+ ABS_MT_POSITION_X, posx2);
+ input_report_abs(tsdata->input,
+ ABS_MT_POSITION_Y, posy2);
+ input_mt_sync(tsdata->input);
+ }
+ } else
+ input_report_key(tsdata->input, BTN_TOUCH, 0);
+
+ input_sync(tsdata->input);
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+ struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+ while (!tsdata->exiting) {
+ pixcir_ts_poscheck(tsdata);
+
+ if (tsdata->chip->attb_read_val())
+ break;
+
+ msleep(20);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pixcir_i2c_ts_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int pixcir_i2c_ts_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+ pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+
+static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
+ struct pixcir_i2c_ts_data *tsdata;
+ struct input_dev *input;
+ int error;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data not defined\n");
+ return -EINVAL;
+ }
+
+ tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!tsdata || !input) {
+ dev_err(&client->dev, "Failed to allocate driver data!\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsdata->client = client;
+ tsdata->input = input;
+ tsdata->chip = pdata;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->dev.parent = &client->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
+
+ input_set_drvdata(input, tsdata);
+
+ error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
+ IRQF_TRIGGER_FALLING,
+ client->name, tsdata);
+ if (error) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_irq;
+
+ i2c_set_clientdata(client, tsdata);
+ device_init_wakeup(&client->dev, 1);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, tsdata);
+err_free_mem:
+ input_free_device(input);
+ kfree(tsdata);
+ return error;
+}
+
+static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
+{
+ struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
+
+ device_init_wakeup(&client->dev, 0);
+
+ tsdata->exiting = true;
+ mb();
+ free_irq(client->irq, tsdata);
+
+ input_unregister_device(tsdata->input);
+ kfree(tsdata);
+
+ return 0;
+}
+
+static const struct i2c_device_id pixcir_i2c_ts_id[] = {
+ { "pixcir_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+
+static struct i2c_driver pixcir_i2c_ts_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pixcir_ts",
+ .pm = &pixcir_dev_pm_ops,
+ },
+ .probe = pixcir_i2c_ts_probe,
+ .remove = __devexit_p(pixcir_i2c_ts_remove),
+ .id_table = pixcir_i2c_ts_id,
+};
+
+static int __init pixcir_i2c_ts_init(void)
+{
+ return i2c_add_driver(&pixcir_i2c_ts_driver);
+}
+module_init(pixcir_i2c_ts_init);
+
+static void __exit pixcir_i2c_ts_exit(void)
+{
+ i2c_del_driver(&pixcir_i2c_ts_driver);
+}
+module_exit(pixcir_i2c_ts_exit);
+
+MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
+MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
new file mode 100644
index 0000000..7163d91
--- /dev/null
+++ b/include/linux/input/pixcir_ts.h
@@ -0,0 +1,10 @@
+#ifndef _PIXCIR_I2C_TS_H
+#define _PIXCIR_I2C_TS_H
+
+struct pixcir_ts_platform_data {
+ int (*attb_read_val)(void);
+ int x_max;
+ int y_max;
+};
+
+#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-07-09 20:12 ` Dmitry Torokhov
@ 2011-07-23 18:18 ` Henrik Rydberg
0 siblings, 0 replies; 8+ messages in thread
From: Henrik Rydberg @ 2011-07-23 18:18 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: jcbian, linux-input, dqmeng, zlchen
On Sat, Jul 09, 2011 at 01:12:10PM -0700, Dmitry Torokhov wrote:
> On Tue, Jul 05, 2011 at 09:30:20PM +0200, Henrik Rydberg wrote:
> >
> > If the above function handles zero fingers as well, the MT finger
> > count comes out wrong in that case.
> >
>
> Hmm, indeed. How about the patch below instead?
Looks good, thanks.
Acked-by: Henrik Rydberg <rydberg@euromail.se>
> +static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +{
> + struct pixcir_i2c_ts_data *tsdata = data;
> + u8 rdbuf[10], wrbuf[1] = { 0 };
> + u8 touch, old_touch;
> + int ret;
> +
> + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
> + if (ret != sizeof(wrbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_send failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> + if (ret != sizeof(rdbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_recv failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + touch = rdbuf[0];
> + old_touch = rdbuf[1];
> + if (touch) {
> + u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
> + u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
> + u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
> + u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
> +
> + input_report_key(tsdata->input, BTN_TOUCH, 1);
> + input_report_abs(tsdata->input, ABS_X, posx1);
> + input_report_abs(tsdata->input, ABS_Y, posy1);
> +
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
> + input_mt_sync(tsdata->input);
> +
> + if (touch == 2) {
> + input_report_abs(tsdata->input,
> + ABS_MT_POSITION_X, posx2);
> + input_report_abs(tsdata->input,
> + ABS_MT_POSITION_Y, posy2);
> + input_mt_sync(tsdata->input);
> + }
> + } else {
> + input_report_key(tsdata->input, BTN_TOUCH, 0);
> + if (old_touch)
> + input_mt_sync(tsdata->input);
> + }
> +
> + input_sync(tsdata->input);
> +}
Henrik
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3] input: add driver for pixcir i2c touchscreens
2011-07-14 2:21 ` jcbian
@ 2011-07-23 18:24 ` Henrik Rydberg
0 siblings, 0 replies; 8+ messages in thread
From: Henrik Rydberg @ 2011-07-23 18:24 UTC (permalink / raw)
To: jcbian; +Cc: Dmitry Torokhov, linux-input, dqmeng, zlchen
On Thu, Jul 14, 2011 at 10:21:57AM +0800, jcbian wrote:
> Hi Dmitry & Henrik,
>
> Thanks for your suggestions and modification .I have test it and it works well.
> Indeed,I think the old_touch is not needed,the follow
>
> + if (old_touch)
> + input_mt_sync(tsdata->input);
>
> could be removed. So,How about below?
Also fine, although the removed brackets is a slight style
violation. No need to resend though.
> +static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +{
> + struct pixcir_i2c_ts_data *tsdata = data;
> + u8 rdbuf[10], wrbuf[1] = { 0 };
> + u8 touch, old_touch;
> + int ret;
> +
> + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
> + if (ret != sizeof(wrbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_send failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> + if (ret != sizeof(rdbuf)) {
> + dev_err(&tsdata->client->dev,
> + "%s: i2c_master_recv failed(), ret=%d\n",
> + __func__, ret);
> + return;
> + }
> +
> + touch = rdbuf[0];
> + old_touch = rdbuf[1];
> + if (touch) {
> + u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
> + u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
> + u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
> + u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
> +
> + input_report_key(tsdata->input, BTN_TOUCH, 1);
> + input_report_abs(tsdata->input, ABS_X, posx1);
> + input_report_abs(tsdata->input, ABS_Y, posy1);
> +
> + input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
> + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
> + input_mt_sync(tsdata->input);
> +
> + if (touch == 2) {
> + input_report_abs(tsdata->input,
> + ABS_MT_POSITION_X, posx2);
> + input_report_abs(tsdata->input,
> + ABS_MT_POSITION_Y, posy2);
> + input_mt_sync(tsdata->input);
> + }
> + } else
> + input_report_key(tsdata->input, BTN_TOUCH, 0);
> +
> + input_sync(tsdata->input);
> +}
Thanks,
Henrik
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-07-23 18:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-24 3:25 [PATCH v3] input: add driver for pixcir i2c touchscreens jcbian
2011-07-04 16:50 ` Dmitry Torokhov
2011-07-05 19:30 ` Henrik Rydberg
2011-07-09 20:12 ` Dmitry Torokhov
2011-07-23 18:18 ` Henrik Rydberg
2011-07-14 2:21 ` jcbian
2011-07-23 18:24 ` Henrik Rydberg
2011-07-04 20:49 ` Henrik Rydberg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).