Skip to contentSkip to conversation

Driver for AUO In-Cell touchscreens using pixcir ICs

PATCH Superseded Heiko Stübner 2 participants 4 messages Dec 5, 2011 – Dec 7, 2011

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 Driver for AUO In-Cell touchscreens using pixcir ICs

Some displays from AUO have a so called in-cell touchscreen, meaning it is built directly into the display unit.

Touchdata is gathered through PIXCIR Tango-ICs and processed in an Atmel ATmega168P with custom firmware. Communication between the host system and ATmega is done via I2C.

Devices using this touch solution include the Dell Streak5 and the family of Qisda ebook readers.

The driver reports single- and multi-touch events including touch area values.

---
changes since v1: address comments from Christoph Fritz (wrong type for error checks, wrong call to input_free_device)

 drivers/input/touchscreen/Kconfig         |   14 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/auo-pixcir-ts.c |  656 +++++++++++++++++++++++++++++
 include/linux/input/auo-pixcir-ts.h       |   57 +++
 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/auo-pixcir-ts.c
 create mode 100644 include/linux/input/auo-pixcir-ts.h
drivers/input/touchscreen/Kconfig +14 -0
index 2b456a9..7da474e 100644
@@ -98,6 +98,20 @@ config TOUCHSCREEN_ATMEL_MXT
 	  To compile this driver as a module, choose M here: the
 	  module will be called atmel_mxt_ts.
 
+config TOUCHSCREEN_AUO_PIXCIR
+	tristate "AUO in-cell touchscreen using Pixcir ICs"
+	depends on I2C
+	depends on GPIOLIB
+	default n
+	help
+	  Say Y here if you have a AUO display with in-cell touchscreen
+	  using Pixcir ICs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called auo-pixcir-ts.
+
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
 	depends on SA1100_BITSY
drivers/input/touchscreen/Makefile +1 -0
index a09c546..f0b4d16 100644
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
+obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
drivers/input/touchscreen/auo-pixcir-ts.c new file +656 -0

656 lines not on this page · raw message

include/linux/input/auo-pixcir-ts.h new file +57 -0

57 lines not on this page · raw message

Signature · 1 line
1.7.5.4
maintainer
#1 lore raw

Hi Heiko,

Quoted 31 lines · Heiko Stübner

Some displays from AUO have a so called in-cell touchscreen, meaning it is built directly into the display unit.

Touchdata is gathered through PIXCIR Tango-ICs and processed in an Atmel ATmega168P with custom firmware. Communication between the host system and ATmega is done via I2C.

Devices using this touch solution include the Dell Streak5 and the family of Qisda ebook readers.

The driver reports single- and multi-touch events including touch area values.

---
changes since v1: address comments from Christoph Fritz (wrong type for error checks, wrong call to input_free_device)

 drivers/input/touchscreen/Kconfig         |   14 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/auo-pixcir-ts.c |  656 +++++++++++++++++++++++++++++
 include/linux/input/auo-pixcir-ts.h       |   57 +++
 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/auo-pixcir-ts.c
 create mode 100644 include/linux/input/auo-pixcir-ts.h
drivers/input/touchscreen/Kconfig +0 -0
index 2b456a9..7da474e 100644

drivers/input/touchscreen/Kconfig config TOUCHSCREEN_ATMEL_MXT · line 105

Quoted 8 lines
drivers/input/touchscreen/Kconfig +5 -0
@@ -98,6 +98,20 @@ config TOUCHSCREEN_ATMEL_MXT
 	  To compile this driver as a module, choose M here: the
 	  module will be called atmel_mxt_ts.
 
+config TOUCHSCREEN_AUO_PIXCIR
+	tristate "AUO in-cell touchscreen using Pixcir ICs"
+	depends on I2C
+	depends on GPIOLIB
+	default n

No need for "default n"

Quoted 30 lines
drivers/input/touchscreen/Kconfig +9 -0
+	help
+	  Say Y here if you have a AUO display with in-cell touchscreen
+	  using Pixcir ICs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called auo-pixcir-ts.
+
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
 	depends on SA1100_BITSY
drivers/input/touchscreen/Makefile +1 -0
index a09c546..f0b4d16 100644
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
+obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
drivers/input/touchscreen/auo-pixcir-ts.c new file +0 -0
new file mode 100644
index 0000000..91a06d2

drivers/input/touchscreen/auo-pixcir-ts.c line 1

Quoted 1 line
drivers/input/touchscreen/auo-pixcir-ts.c new file +1 -0
@@ -0,0 +1,656 @@
+/* drivers/input/touchscreen/auo-pixcir-ts.c

Please no file names in files - this way you don't need to change it here if you rename it later.

Quoted 19 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +19 -0
+ *
+ * Copyright (c) 2011 Heiko Stuebner <[email protected]>
+ *
+ * loosely based on auo_touch.c from Dell Streak vendor-kernel
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, 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.
+ *
+ */

drivers/input/touchscreen/auo-pixcir-ts.c line 30

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>

Do you need this?

drivers/input/touchscreen/auo-pixcir-ts.c line 31

Quoted 1 line
drivers/input/touchscreen/auo-pixcir-ts.c new file +1 -0
+#include <linux/miscdevice.h>

And this?

drivers/input/touchscreen/auo-pixcir-ts.c line 33

Quoted 2 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +2 -0
+#include <linux/i2c.h>
+#include <linux/semaphore.h>

I think you want mutex.h instead.

Quoted 183 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +183 -0
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input/auo-pixcir-ts.h>
+
+/*
+ * Coordinate calculation:
+ * X1 = X1_LSB + X1_MSB*256
+ * Y1 = Y1_LSB + Y1_MSB*256
+ * X2 = X2_LSB + X2_MSB*256
+ * Y2 = Y2_LSB + Y2_MSB*256
+ */
+#define AUO_PIXCIR_REG_X1_LSB		0x00
+#define AUO_PIXCIR_REG_X1_MSB		0x01
+#define AUO_PIXCIR_REG_Y1_LSB		0x02
+#define AUO_PIXCIR_REG_Y1_MSB		0x03
+#define AUO_PIXCIR_REG_X2_LSB		0x04
+#define AUO_PIXCIR_REG_X2_MSB		0x05
+#define AUO_PIXCIR_REG_Y2_LSB		0x06
+#define AUO_PIXCIR_REG_Y2_MSB		0x07
+
+#define AUO_PIXCIR_REG_STRENGTH		0x0d
+#define AUO_PIXCIR_REG_STRENGTH_X1_LSB	0x0e
+#define AUO_PIXCIR_REG_STRENGTH_X1_MSB	0x0f
+
+#define AUO_PIXCIR_REG_RAW_DATA_X	0x2b
+#define AUO_PIXCIR_REG_RAW_DATA_Y	0x4f
+
+#define AUO_PIXCIR_REG_X_SENSITIVITY	0x6f
+#define AUO_PIXCIR_REG_Y_SENSITIVITY	0x70
+#define AUO_PIXCIR_REG_INT_SETTING	0x71
+#define AUO_PIXCIR_REG_INT_WIDTH	0x72
+#define AUO_PIXCIR_REG_POWER_MODE	0x73
+
+#define AUO_PIXCIR_REG_VERSION		0x77
+#define AUO_PIXCIR_REG_CALIBRATE	0x78
+
+#define AUO_PIXCIR_REG_TOUCHAREA_X1	0x1e
+#define AUO_PIXCIR_REG_TOUCHAREA_Y1	0x1f
+#define AUO_PIXCIR_REG_TOUCHAREA_X2	0x20
+#define AUO_PIXCIR_REG_TOUCHAREA_Y2	0x21
+
+#define AUO_PIXCIR_REG_EEPROM_CALIB_X	0x42
+#define AUO_PIXCIR_REG_EEPROM_CALIB_Y	0xad
+
+#define AUO_PIXCIR_INT_TPNUM_MASK	0xe0
+#define AUO_PIXCIR_INT_TPNUM_SHIFT	5
+#define AUO_PIXCIR_INT_RELEASE		(1 << 4)
+#define AUO_PIXCIR_INT_ENABLE		(1 << 3)
+#define AUO_PIXCIR_INT_POL_HIGH		(1 << 2)
+#define AUO_PIXCIR_INT_MODE_MASK	0x03
+
+/*
+ * Power modes:
+ * active:	scan speed 60Hz
+ * sleep:	scan speed 10Hz can be auto-activated, wakeup on 1st touch
+ * deep sleep:	scan speed 1Hz can only be entered or left manually.
+ */
+#define AUO_PIXCIR_POWER_ACTIVE		0x00
+#define AUO_PIXCIR_POWER_SLEEP		0x01
+#define AUO_PIXCIR_POWER_DEEP_SLEEP	0x02
+#define AUO_PIXCIR_POWER_MASK		0x03
+
+#define AUO_PIXCIR_POWER_ALLOW_SLEEP	(1 << 2)
+#define AUO_PIXCIR_POWER_IDLE_TIME(ms)	((ms & 0xf) << 4)
+
+#define AUO_PIXCIR_CALIBRATE		0x03
+
+#define AUO_PIXCIR_EEPROM_CALIB_X_LEN	62
+#define AUO_PIXCIR_EEPROM_CALIB_Y_LEN	36
+
+#define AUO_PIXCIR_RAW_DATA_X_LEN	18
+#define AUO_PIXCIR_RAW_DATA_Y_LEN	11
+
+#define AUO_PIXCIR_STRENGTH_ENABLE	(1 << 0)
+
+/* Touchscreen absolute values */
+#define AUO_PIXCIR_REPORT_POINTS	2
+#define AUO_PIXCIR_MAX_AREA		0xff
+#define AUO_PIXCIR_PENUP_TIMEOUT_MS	10
+
+struct auo_pixcir_ts {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	char			phys[32];
+
+	/* special handling for touch_indicate interupt mode */
+	bool			touch_ind_mode;
+
+	wait_queue_head_t	wait;
+	bool			stopped;
+	bool			is_open;
+};
+
+struct auo_point_t {
+	int	coord_x;
+	int	coord_y;
+	int	area_major;
+	int	area_minor;
+	int	orientation;
+};
+
+static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
+				   struct auo_point_t *point)
+{
+	struct i2c_client *client = ts->client;
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	uint8_t raw_coord[8];
+	uint8_t raw_area[4];
+	int i, ret;
+
+	/* touch coordinates */
+	ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB,
+					    8, raw_coord);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read coordinate, %d\n", ret);
+		return ret;
+	}
+
+	/* touch area */
+	ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1,
+					    4, raw_area);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not read touch area, %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+		point[i].coord_x = raw_coord[4*i+1] << 8 | raw_coord[4*i];
+		point[i].coord_y = raw_coord[4*i+3] << 8 | raw_coord[4*i+2];
+
+		if (point[i].coord_x > pdata->x_max ||
+		    point[i].coord_y > pdata->y_max) {
+			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
+				point[i].coord_x, point[i].coord_y);
+			point[i].coord_x = point[i].coord_y = 0;
+		}
+
+		/* determine touch major, minor and orientation */
+		point[i].area_major = max(raw_area[2*i], raw_area[2*i+1]);
+		point[i].area_minor = min(raw_area[2*i], raw_area[2*i+1]);
+		point[i].orientation = (raw_area[2*i] > raw_area[2*i+1]);
+	}
+
+	return 0;
+}
+
+static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
+{
+	struct auo_pixcir_ts *ts = dev_id;
+	struct i2c_client *client = ts->client;
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
+	int i;
+	int ret;
+	int fingers = 0;
+	int abs = -1;
+
+	while (!ts->stopped) {
+
+		/* check for up event in touch touch_ind_mode */
+		if (ts->touch_ind_mode) {
+			if (gpio_get_value(pdata->gpio_int) == 0) {
+				input_mt_sync(ts->input);
+				input_report_key(ts->input, BTN_TOUCH, 0);
+				input_sync(ts->input);
+				break;
+			}
+		}
+
+		ret = auo_pixcir_collect_data(ts, point);
+		if (ret < 0) {
+			/* we want to loop only in touch_ind_mode */
+			if (!ts->touch_ind_mode)
+				break;
+
+			wait_event_timeout(ts->wait, ts->stopped,
+				msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
+			continue;
+		}
+
+		for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+			if (point[i].coord_x > 0 || point[i].coord_y > 0) {
+				input_report_abs(ts->input, ABS_MT_POSITION_X,

drivers/input/touchscreen/auo-pixcir-ts.c line 226

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+						 point[i].coord_x);
+				input_report_abs(ts->input, ABS_MT_POSITION_Y,
+						 point[i].coord_y);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+						 point[i].area_major);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
+						 point[i].area_minor);
+				input_report_abs(ts->input, ABS_MT_ORIENTATION,
+						 point[i].orientation);
+				input_mt_sync(ts->input);

Is there a way to track the contacts and switch to protocol B by any chance?

Quoted 55 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +55 -0
+
+				/* use first finger as source for singletouch */
+				if (fingers == 0)
+					abs = i;
+
+				/* number of touch points could also be queried
+				 * via i2c but would require an additional call
+				 */
+				fingers++;
+			}
+		}
+
+		input_report_key(ts->input, BTN_TOUCH, fingers > 0);
+
+		if (abs > -1) {
+			input_report_abs(ts->input, ABS_X, point[abs].coord_x);
+			input_report_abs(ts->input, ABS_Y, point[abs].coord_y);
+		}
+
+		input_sync(ts->input);
+
+		/* we want to loop only in touch_ind_mode */
+		if (!ts->touch_ind_mode)
+			break;
+
+		wait_event_timeout(ts->wait, ts->stopped,
+				 msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Set the power mode of the device.
+ * Valid modes are
+ * - AUO_PIXCIR_POWER_ACTIVE
+ * - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch
+ * - AUO_PIXCIR_POWER_DEEP_SLEEP
+ */
+static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	ret &= (~AUO_PIXCIR_POWER_MASK);
+	ret |= mode;
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret);

drivers/input/touchscreen/auo-pixcir-ts.c line 291

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+	if (ret) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_int_config(struct auo_pixcir_ts *ts, int int_setting)

__devinit?

Quoted 18 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +18 -0
+{
+	struct i2c_client *client = ts->client;
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	ret &= (~AUO_PIXCIR_INT_MODE_MASK);
+	ret |= int_setting;
+	ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
+					ret);

drivers/input/touchscreen/auo-pixcir-ts.c line 319

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	if (pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND)
+		ts->touch_ind_mode = 1;
+	else
+		ts->touch_ind_mode = 0;
	ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND;

drivers/input/touchscreen/auo-pixcir-ts.c line 324

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+
+	return 0;
+}
+
+/* controll the generation of interrupts on the device side */

Typo: control

drivers/input/touchscreen/auo-pixcir-ts.c line 325

Quoted 1 line
drivers/input/touchscreen/auo-pixcir-ts.c new file +1 -0
+static int auo_pixcir_int_enable(struct auo_pixcir_ts *ts, int enable)

bool enable

Probably call it "auo_pixcir_int_toggle".

drivers/input/touchscreen/auo-pixcir-ts.c line 334

Quoted 9 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +9 -0
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		disable_irq(client->irq);

This looks like wrong place for disable_irq(). Caller should do it IMO.

Quoted 87 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +87 -0
+		return ret;
+	}
+
+	if (enable)
+		ret |= AUO_PIXCIR_INT_ENABLE;
+	else
+		ret &= ~AUO_PIXCIR_INT_ENABLE;
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
+					ret);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		disable_irq(client->irq);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_start(struct auo_pixcir_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not set power mode, %d\n",
+			ret);
+		return ret;
+	}
+
+	ts->stopped = false;
+	mb();
+	enable_irq(client->irq);
+
+	ret = auo_pixcir_int_enable(ts, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not enable interrupt, %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = auo_pixcir_int_enable(ts, 0);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not disable interrupt, %d\n",
+			ret);
+		return ret;
+	}
+
+	/* disable receiving of interrupts */
+	disable_irq(client->irq);
+	ts->stopped = true;
+	mb();
+	wake_up(&ts->wait);
+
+	return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP);
+}
+
+static int auo_pixcir_input_open(struct input_dev *dev)
+{
+	struct auo_pixcir_ts *ts = input_get_drvdata(dev);
+	int ret;
+
+	ret = auo_pixcir_start(ts);
+	if (ret)
+		return ret;
+
+	ts->is_open = true;
+
+	return 0;
+}
+
+static void auo_pixcir_input_close(struct input_dev *dev)
+{
+	struct auo_pixcir_ts *ts = input_get_drvdata(dev);
+
+	ts->is_open = false;
+

drivers/input/touchscreen/auo-pixcir-ts.c line 431

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+	auo_pixcir_stop(ts);
+
+	return;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int auo_pixcir_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct auo_pixcir_ts *ts = (struct auo_pixcir_ts *)

The cast is not needed.

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+						i2c_get_clientdata(client);
+
+	/* if device isn't open it's stopped already */
+	if (ts->is_open) {
+		if (device_may_wakeup(&client->dev)) {
+			enable_irq_wake(client->irq);
+			return auo_pixcir_power_mode(ts,
+						     AUO_PIXCIR_POWER_SLEEP);
+		} else {
+			auo_pixcir_stop(ts);

drivers/input/touchscreen/auo-pixcir-ts.c line 451

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+		}
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct auo_pixcir_ts *ts = (struct auo_pixcir_ts *)

The cast is not needed.

drivers/input/touchscreen/auo-pixcir-ts.c line 454

Quoted 3 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +3 -0
+						i2c_get_clientdata(client);
+
+	/* if device isn't open it was stopped and should stay that way */

If it is configured as wakeup source it should still wake up the system.

drivers/input/touchscreen/auo-pixcir-ts.c line 459

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+	if (ts->is_open) {
+		if (device_may_wakeup(&client->dev)) {
+			disable_irq_wake(client->irq);
+			/* automatic wakeup on first-touch */
+		} else if (ts->is_open) {

This needs locking WRT open/close. You can use input->users and input->mutex instead of ts->is_open.

drivers/input/touchscreen/auo-pixcir-ts.c line 467

Quoted 8 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +8 -0
+			return auo_pixcir_start(ts);
+		}
+	}
+
+	return 0;
+}
+
+SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend, auo_pixcir_resume);

static and pull it out of #ifdef and you can drop #ifdef in driver definition as well.

Quoted 20 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +20 -0
+#endif
+
+static int __devinit auo_pixcir_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct auo_pixcir_ts *ts;
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	struct input_dev *input_dev;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int");
+	if (ret) {
+		dev_err(&client->dev, "request of gpio %d failed, %d\n",

drivers/input/touchscreen/auo-pixcir-ts.c line 497

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+			pdata->gpio_int, ret);
+		goto err_gpio_int;
+	}
+
+	ret = gpio_request(pdata->gpio_rst, "auo_pixcir_ts_rst");
+	if (ret) {
+		dev_err(&client->dev, "request of gpio %d failed, %d\n",
+			pdata->gpio_int, ret);
+		goto err_gpio_rst;
+	}

I do not see it actually being used?

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+
+	if (pdata->init_hw)
+		pdata->init_hw();
+
+	ts->client = client;
+	ts->touch_ind_mode = 0;
+	init_waitqueue_head(&ts->wait);
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));

drivers/input/touchscreen/auo-pixcir-ts.c line 517

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&client->dev, "could not allocate input device\n");
+		goto err_input_alloc;
+	}
+
+	ts->input = input_dev;
+
+	input_dev->name = "auo_pixcir_ts";

Could do with a better name I think. It does not need to resemble file name.

Quoted 51 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +51 -0
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_dev->open = auo_pixcir_input_open;
+	input_dev->close = auo_pixcir_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0);
+
+	/* For multi touch */
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+			     pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+			     pdata->y_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
+			     AUO_PIXCIR_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
+			     AUO_PIXCIR_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
+	if (ret < 0)
+		goto err_fw_vers;
+	dev_info(&client->dev, "firmware version 0x%X\n", ret);
+
+	ret = auo_pixcir_int_config(ts, pdata->int_setting);
+	if (ret)
+		goto err_fw_vers;
+
+	/* disable irqs on the device side before irq-request */
+	auo_pixcir_int_enable(ts, 0);
+	ts->stopped = true;
+	ts->is_open = false;
+
+	ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt,
+				   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				   input_dev->name, ts);
+	if (ret) {
+		dev_err(&client->dev, "irq %d requested failed\n", client->irq);
+		goto err_fw_vers;
+	}
+
+	/* stop device and put it into deep sleep until it is opened */
+	ret = auo_pixcir_stop(ts);

drivers/input/touchscreen/auo-pixcir-ts.c line 578

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+	if (ret < 0)
+		goto err_input_register;
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		dev_err(&client->dev, "could not register input device\n");
+		goto err_input_register;
+	}
+
+	input_set_drvdata(ts->input, ts);

Just do this earlier and then auo_pixcir_stop() is enough, you won't need to call auo_pixcir_int_enable() before registering IRQ.

Quoted 14 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +14 -0
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+
+err_input_register:
+	free_irq(client->irq, ts);
+err_fw_vers:
+	input_free_device(input_dev);
+err_input_alloc:
+	if (pdata->exit_hw)
+		pdata->exit_hw();
+	gpio_free(pdata->gpio_rst);
+err_gpio_rst:

drivers/input/touchscreen/auo-pixcir-ts.c line 602

Quoted 10 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +10 -0
+	gpio_free(pdata->gpio_int);
+err_gpio_int:
+	kfree(ts);
+
+	return ret;
+}
+
+static int __devexit auo_pixcir_remove(struct i2c_client *client)
+{
+	struct auo_pixcir_ts *ts = (struct auo_pixcir_ts *)

No need to cast.

drivers/input/touchscreen/auo-pixcir-ts.c line 604

Quoted 2 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +2 -0
+						i2c_get_clientdata(client);
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;

const.

drivers/input/touchscreen/auo-pixcir-ts.c line 606

Quoted 2 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +2 -0
+
+	auo_pixcir_stop(ts);

This should not be needed as the device should be closed at this point.

Quoted 83 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +50 -0
+
+	free_irq(client->irq, ts);
+
+	input_unregister_device(ts->input);
+
+	if (pdata->exit_hw)
+		pdata->exit_hw();
+
+	gpio_free(pdata->gpio_int);
+	gpio_free(pdata->gpio_rst);
+
+	kfree(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id auo_pixcir_idtable[] = {
+	{ "auo_pixcir_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
+
+static struct i2c_driver auo_pixcir_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "auo_pixcir_ts",
+#ifdef CONFIG_PM
+		.pm	= &auo_pixcir_pm_ops,
+#endif
+	},
+	.probe		= auo_pixcir_probe,
+	.remove		= __devexit_p(auo_pixcir_remove),
+	.id_table	= auo_pixcir_idtable,
+};
+
+static int __init auo_pixcir_init(void)
+{
+	return i2c_add_driver(&auo_pixcir_driver);
+}
+module_init(auo_pixcir_init);
+
+static void __exit auo_pixcir_exit(void)
+{
+	i2c_del_driver(&auo_pixcir_driver);
+}
+module_exit(auo_pixcir_exit);
+
+MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <[email protected]>");
include/linux/input/auo-pixcir-ts.h new file +27 -0
new file mode 100644
index 0000000..d4221be
@@ -0,0 +1,57 @@
+/* drivers/input/touchscreen/auo-pixcir-ts.h
+ *
+ * Copyright (c) 2011 Heiko Stuebner <[email protected]>
+ *
+ * based on auo_touch.h from Dell Streak kernel
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, 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.
+ *
+ */
+
+#ifndef __AUO_PIXCIR_TS_H__
+#define __AUO_PIXCIR_TS_H__
+
+/*
+ * Interrupt modes:
+ * periodical:		interrupt is asserted periodicaly

include/linux/input/auo-pixcir-ts.h line 37

Quoted 10 lines
include/linux/input/auo-pixcir-ts.h new file +10 -0
+ * compare coordinates:	interrupt is asserted when coordinates change
+ * indicate touch:	interrupt is asserted during touch
+ */
+#define AUO_PIXCIR_INT_PERIODICAL	0x00
+#define AUO_PIXCIR_INT_COMP_COORD	0x01
+#define AUO_PIXCIR_INT_TOUCH_IND	0x02
+
+/*
+ * @gpio_int		interrupt gpio
+ * @gpio_rst		reset gpio, used in init_hw and exit_hw

OK, if it is used by platform code only then it should not be here.

include/linux/input/auo-pixcir-ts.h line 50

Quoted 13 lines
include/linux/input/auo-pixcir-ts.h new file +13 -0
+ * @int_setting		one of AUO_PIXCIR_INT_*
+ * @init_hw		hardwarespecific init
+ * @exit_hw		hardwarespecific shutdown
+ * @x_max		x-resolution
+ * @y_max		y-resolution
+ */
+struct auo_pixcir_ts_platdata {
+	int gpio_int;
+	int gpio_rst;
+
+	int int_setting;
+
+	void (*init_hw)(void);

Maybe pass client or device so that we could theoretically handle multiple devices?

Quoted 10 lines
include/linux/input/auo-pixcir-ts.h new file +7 -0
+	void (*exit_hw)(void);
+
+	unsigned int x_max;
+	unsigned int y_max;
+};
+
+#endif
Signature · 1 line
1.7.5.4

Thanks.

Signature · 5 lines
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#2 lore raw

Hi Dmitry,

thanks for the review

Am Dienstag, 6. Dezember 2011, 06:56:37 schrieb Dmitry Torokhov:

Quoted 19 lines · Heiko Stübner
Quoted 18 lines

Some displays from AUO have a so called in-cell touchscreen, meaning it is built directly into the display unit.

Touchdata is gathered through PIXCIR Tango-ICs and processed in an Atmel ATmega168P with custom firmware. Communication between the host system and ATmega is done via I2C.

Devices using this touch solution include the Dell Streak5 and the family of Qisda ebook readers.

The driver reports single- and multi-touch events including touch area values.

---
changes since v1: address comments from Christoph Fritz (wrong type for error checks, wrong call to input_free_device)

Quoted 9 lines
Quoted 9 lines
 drivers/input/touchscreen/Kconfig         |   14 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/auo-pixcir-ts.c |  656
 +++++++++++++++++++++++++++++ include/linux/input/auo-pixcir-ts.h      
 |   57 +++
 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/auo-pixcir-ts.c
 create mode 100644 include/linux/input/auo-pixcir-ts.h

[ ... small corrections, thanks for finding them ... ]

Quoted 9 lines
Quoted 9 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +9 -0
+
+		for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+			if (point[i].coord_x > 0 || point[i].coord_y > 0) {
+				input_report_abs(ts->input, ABS_MT_POSITION_X,
+						 point[i].coord_x);
+				input_report_abs(ts->input, ABS_MT_POSITION_Y,
+						 point[i].coord_y);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+						 point[i].area_major);
Quoted 8 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 226

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+				input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
+						 point[i].area_minor);
+				input_report_abs(ts->input, ABS_MT_ORIENTATION,
+						 point[i].orientation);
+				input_mt_sync(ts->input);

Is there a way to track the contacts and switch to protocol B by any chance?

I'm not sure, but will check how the device handles changing the number of touching fingers and if it would be possible to switch.

Quoted 11 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 237

Quoted 11 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +11 -0
+
+				/* use first finger as source for singletouch */
+				if (fingers == 0)
+					abs = i;
+
+				/* number of touch points could also be queried
+				 * via i2c but would require an additional call
+				 */
+				fingers++;
+			}
+		}

[ ... more small stuff for me to fix ... ]

Quoted 11 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 578

Quoted 8 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +8 -0
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		dev_err(&client->dev, "could not register input device\n");
+		goto err_input_register;
+	}
+
+	input_set_drvdata(ts->input, ts);

Just do this earlier and then auo_pixcir_stop() is enough, you won't need to call auo_pixcir_int_enable() before registering IRQ.

Just to be sure, you mean moving the input_set_drvdata before the irq- registration?

Quoted 5 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 583

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+

[ ... and still more small stuff ]

Thanks
Heiko
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

Am Mittwoch 07 Dezember 2011, 15:31:20 schrieb Heiko Stübner:

Quoted 55 lines

Hi Dmitry,

thanks for the review

Am Dienstag, 6. Dezember 2011, 06:56:37 schrieb Dmitry Torokhov:

Quoted 24 lines · Heiko Stübner
Quoted 23 lines

Some displays from AUO have a so called in-cell touchscreen, meaning it is built directly into the display unit.

Touchdata is gathered through PIXCIR Tango-ICs and processed in an Atmel ATmega168P with custom firmware. Communication between the host system and ATmega is done via I2C.

Devices using this touch solution include the Dell Streak5 and the family of Qisda ebook readers.

The driver reports single- and multi-touch events including touch area values.

---
changes since v1: address comments from Christoph Fritz (wrong type for error checks, wrong call to input_free_device)

 drivers/input/touchscreen/Kconfig         |   14 +
 drivers/input/touchscreen/Makefile        |    1 +
 drivers/input/touchscreen/auo-pixcir-ts.c |  656

+++++++++++++++++++++++++++++ include/linux/input/auo-pixcir-ts.h

Quoted 5 lines
Quoted 5 lines

| 57 +++

 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/auo-pixcir-ts.c
 create mode 100644 include/linux/input/auo-pixcir-ts.h

[ ... small corrections, thanks for finding them ... ]

Quoted 9 lines
Quoted 9 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +9 -0
+
+		for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+			if (point[i].coord_x > 0 || point[i].coord_y > 0) {
+				input_report_abs(ts->input, ABS_MT_POSITION_X,
+						 point[i].coord_x);
+				input_report_abs(ts->input, ABS_MT_POSITION_Y,
+						 point[i].coord_y);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+						 point[i].area_major);
Quoted 8 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 226

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+				input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
+						 point[i].area_minor);
+				input_report_abs(ts->input, ABS_MT_ORIENTATION,
+						 point[i].orientation);
+				input_mt_sync(ts->input);

Is there a way to track the contacts and switch to protocol B by any chance?

Quoted 2 lines

I'm not sure, but will check how the device handles changing the number of touching fingers and if it would be possible to switch.

Sadly, the device does not seem capable of really tracking the contacts individually.
My testcase:
- p0 <-> finger0, p1 <-> finger1
- finger0 is lifted
in todays test: new mapping finger1 <-> p0
some time ago during another test sometimes it did this switch and sometimes not, so the mapping reported point <-> finger is probably not stable.

Quoted 26 lines
Quoted 11 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 237

Quoted 11 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +11 -0
+
+				/* use first finger as source for singletouch */
+				if (fingers == 0)
+					abs = i;
+
+				/* number of touch points could also be queried
+				 * via i2c but would require an additional call
+				 */
+				fingers++;
+			}
+		}

[ ... more small stuff for me to fix ... ]

Quoted 11 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 578

Quoted 8 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +8 -0
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		dev_err(&client->dev, "could not register input device\n");
+		goto err_input_register;
+	}
+
+	input_set_drvdata(ts->input, ts);

Just do this earlier and then auo_pixcir_stop() is enough, you won't need to call auo_pixcir_int_enable() before registering IRQ.

Quoted 2 lines

Just to be sure, you mean moving the input_set_drvdata before the irq- registration?

seems to work

Quoted 10 lines
Quoted 5 lines

drivers/input/touchscreen/auo-pixcir-ts.c line 583

Quoted 5 lines
drivers/input/touchscreen/auo-pixcir-ts.c new file +5 -0
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+

[ ... and still more small stuff ]

Thanks
Heiko

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html