All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support
@ 2014-05-06 11:06 ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Hi Dmitry,

This series does the following

- use devres managed resource allocations
- convert to Type-B multi touch protocol
- support upto 5 fingers with hardware supplied tracking IDs
- device tree support

Please queue this for -next (3.16). Thanks.

cheers,
-roger

Changelog:

v5:
- Changed ts->exiting flag to ts->running in patch 2.
- Don't call pixcir_stop() from .suspend() if wakeup is required.

v4:
- Imporved pixcir_stop() as per Dmitry's suggestion.
- Removed unnecessary input_unregister_device() from .remove().

v3:
- Rebased to 3.15-rc3
- Fixed suspend while touchscreen in use
- Fixed module removal while touchscreen in use

v2:
- Addressed review comments and re-arranged patch order

v1:
- http://article.gmane.org/gmane.linux.kernel/1616417

--
Roger Quadros (7):
  Input: pixcir_i2c_ts: Use devres managed resource allocations
  Input: pixcir_i2c_ts - initialize interrupt mode and power mode
  Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
  Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided
    tracking IDs
  Input: pixcir_i2c_ts: Implement wakeup from suspend
  Input: pixcir_i2c_ts: Add device tree support

 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   |  26 +
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 524 ++++++++++++++++++---
 include/linux/input/pixcir_ts.h                    |  56 ++-
 4 files changed, 540 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

-- 
1.8.3.2


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

* [PATCH v5 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support
@ 2014-05-06 11:06 ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Hi Dmitry,

This series does the following

- use devres managed resource allocations
- convert to Type-B multi touch protocol
- support upto 5 fingers with hardware supplied tracking IDs
- device tree support

Please queue this for -next (3.16). Thanks.

cheers,
-roger

Changelog:

v5:
- Changed ts->exiting flag to ts->running in patch 2.
- Don't call pixcir_stop() from .suspend() if wakeup is required.

v4:
- Imporved pixcir_stop() as per Dmitry's suggestion.
- Removed unnecessary input_unregister_device() from .remove().

v3:
- Rebased to 3.15-rc3
- Fixed suspend while touchscreen in use
- Fixed module removal while touchscreen in use

v2:
- Addressed review comments and re-arranged patch order

v1:
- http://article.gmane.org/gmane.linux.kernel/1616417

--
Roger Quadros (7):
  Input: pixcir_i2c_ts: Use devres managed resource allocations
  Input: pixcir_i2c_ts - initialize interrupt mode and power mode
  Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
  Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided
    tracking IDs
  Input: pixcir_i2c_ts: Implement wakeup from suspend
  Input: pixcir_i2c_ts: Add device tree support

 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   |  26 +
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 524 ++++++++++++++++++---
 include/linux/input/pixcir_ts.h                    |  56 ++-
 4 files changed, 540 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

-- 
1.8.3.2

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

* [PATCH v5 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations
  2014-05-06 11:06 ` Roger Quadros
@ 2014-05-06 11:06   ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Use devm_() and friends for allocating memory, input device
and IRQ.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 38 ++++++++++++-------------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 02392d2..8a083bd 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -130,6 +130,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
+	struct device *dev = &client->dev;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
@@ -139,12 +140,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		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 = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
+	if (!tsdata)
+		return -ENOMEM;
+
+	input = devm_input_allocate_device(dev);
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
 	}
 
 	tsdata->client = client;
@@ -165,29 +168,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
-	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
-				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-				     client->name, tsdata);
+	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
+					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					  client->name, tsdata);
 	if (error) {
-		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		goto err_free_mem;
+		dev_err(dev, "failed to request irq %d\n", client->irq);
+		return error;
 	}
 
 	error = input_register_device(input);
 	if (error)
-		goto err_free_irq;
+		return error;
 
 	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 pixcir_i2c_ts_remove(struct i2c_client *client)
@@ -198,10 +194,6 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 	tsdata->exiting = true;
 	mb();
-	free_irq(client->irq, tsdata);
-
-	input_unregister_device(tsdata->input);
-	kfree(tsdata);
 
 	return 0;
 }
-- 
1.8.3.2


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

* [PATCH v5 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Use devm_() and friends for allocating memory, input device
and IRQ.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 38 ++++++++++++-------------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 02392d2..8a083bd 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -130,6 +130,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
+	struct device *dev = &client->dev;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
@@ -139,12 +140,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		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 = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
+	if (!tsdata)
+		return -ENOMEM;
+
+	input = devm_input_allocate_device(dev);
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
 	}
 
 	tsdata->client = client;
@@ -165,29 +168,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
-	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
-				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-				     client->name, tsdata);
+	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
+					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					  client->name, tsdata);
 	if (error) {
-		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		goto err_free_mem;
+		dev_err(dev, "failed to request irq %d\n", client->irq);
+		return error;
 	}
 
 	error = input_register_device(input);
 	if (error)
-		goto err_free_irq;
+		return error;
 
 	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 pixcir_i2c_ts_remove(struct i2c_client *client)
@@ -198,10 +194,6 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 	tsdata->exiting = true;
 	mb();
-	free_irq(client->irq, tsdata);
-
-	input_unregister_device(tsdata->input);
-	kfree(tsdata);
 
 	return 0;
 }
-- 
1.8.3.2

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

* [PATCH v5 2/7] Input: pixcir_i2c_ts - initialize interrupt mode and power mode
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Introduce helper functions to configure power and interrupt registers.
Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode
on detecting finger touch.

Configure interrupt mode and polarity on start up.  Power down on device
closure or module removal.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 182 ++++++++++++++++++++++++++++--
 include/linux/input/pixcir_ts.h           |  42 +++++++
 2 files changed, 216 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a083bd..96a1b1e 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
 	const struct pixcir_ts_platform_data *chip;
-	bool exiting;
+	bool running;
 };
 
 static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
@@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 
-	while (!tsdata->exiting) {
+	while (tsdata->running) {
 		pixcir_ts_poscheck(tsdata);
 
 		if (tsdata->chip->attb_read_val())
@@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
+				 enum pixcir_power_mode mode)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_POWER_MODE_MASK;
+	ret |= mode;
+
+	/* Always AUTO_IDLE */
+	ret |= PIXCIR_POWER_ALLOW_IDLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Set the interrupt mode for the device i.e. ATTB line behaviour
+ *
+ * @polarity : 1 for active high, 0 for active low.
+ */
+static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
+			       enum pixcir_int_mode mode, bool polarity)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_INT_MODE_MASK;
+	ret |= mode;
+
+	if (polarity)
+		ret |= PIXCIR_INT_POL_HIGH;
+	else
+		ret &= ~PIXCIR_INT_POL_HIGH;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Enable/disable interrupt generation
+ */
+static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	if (enable)
+		ret |= PIXCIR_INT_ENABLE;
+	else
+		ret &= ~PIXCIR_INT_ENABLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pixcir_start(struct pixcir_i2c_ts_data *ts)
+{
+	struct device *dev = &ts->client->dev;
+	int error;
+
+	/* LEVEL_TOUCH interrupt with active low polarity */
+	error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
+	if (error) {
+		dev_err(dev, "Failed to set interrupt mode: %d\n", error);
+		return error;
+	}
+
+	ts->running = true;
+	mb();	/* Update status before IRQ can fire */
+
+	/* enable interrupt generation */
+	error = pixcir_int_enable(ts, true);
+	if (error) {
+		dev_err(dev, "Failed to enable interrupt generation: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
+{
+	int error;
+
+	/* Disable interrupt generation */
+	error = pixcir_int_enable(ts, false);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"Failed to disable interrupt generation: %d\n",
+			error);
+		return error;
+	}
+
+	/* Exit ISR if running, no more report parsing */
+	ts->running = false;
+	mb();	/* update status before we synchronize irq */
+
+	/* Wait till running ISR is complete */
+	synchronize_irq(ts->client->irq);
+
+	return 0;
+}
+
+static int pixcir_input_open(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	return pixcir_start(ts);
+}
+
+static void pixcir_input_close(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	pixcir_stop(ts);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int pixcir_i2c_ts_suspend(struct device *dev)
 {
@@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
+	input->open = pixcir_input_open;
+	input->close = pixcir_input_close;
 	input->dev.parent = &client->dev;
 
 	__set_bit(EV_KEY, input->evbit);
@@ -176,11 +336,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		return error;
 	}
 
+	/* Always be in IDLE mode to save power, device supports auto wake */
+	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
+	if (error) {
+		dev_err(dev, "Failed to set IDLE mode\n");
+		return error;
+	}
+
+	/* Stop device till opened */
+	error = pixcir_stop(tsdata);
+	if (error)
+		return error;
+
 	error = input_register_device(input);
 	if (error)
 		return error;
 
-	i2c_set_clientdata(client, tsdata);
 	device_init_wakeup(&client->dev, 1);
 
 	return 0;
@@ -188,13 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 static int 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();
-
 	return 0;
 }
 
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7163d91..7942804 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -1,6 +1,48 @@
 #ifndef	_PIXCIR_I2C_TS_H
 #define	_PIXCIR_I2C_TS_H
 
+/*
+ * Register map
+ */
+#define PIXCIR_REG_POWER_MODE	51
+#define PIXCIR_REG_INT_MODE	52
+
+/*
+ * Power modes:
+ * active: max scan speed
+ * idle: lower scan speed with automatic transition to active on touch
+ * halt: datasheet says sleep but this is more like halt as the chip
+ *       clocks are cut and it can only be brought out of this mode
+ *	 using the RESET pin.
+ */
+enum pixcir_power_mode {
+	PIXCIR_POWER_ACTIVE,
+	PIXCIR_POWER_IDLE,
+	PIXCIR_POWER_HALT,
+};
+
+#define PIXCIR_POWER_MODE_MASK	0x03
+#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
+
+/*
+ * Interrupt modes:
+ * periodical: interrupt is asserted periodicaly
+ * diff coordinates: interrupt is asserted when coordinates change
+ * level on touch: interrupt level asserted during touch
+ * pulse on touch: interrupt pulse asserted druing touch
+ *
+ */
+enum pixcir_int_mode {
+	PIXCIR_INT_PERIODICAL,
+	PIXCIR_INT_DIFF_COORD,
+	PIXCIR_INT_LEVEL_TOUCH,
+	PIXCIR_INT_PULSE_TOUCH,
+};
+
+#define PIXCIR_INT_MODE_MASK	0x03
+#define PIXCIR_INT_ENABLE	(1UL << 3)
+#define PIXCIR_INT_POL_HIGH	(1UL << 2)
+
 struct pixcir_ts_platform_data {
 	int (*attb_read_val)(void);
 	int x_max;
-- 
1.8.3.2


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

* [PATCH v5 2/7] Input: pixcir_i2c_ts - initialize interrupt mode and power mode
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0,
	dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0,
	nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros

Introduce helper functions to configure power and interrupt registers.
Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode
on detecting finger touch.

Configure interrupt mode and polarity on start up.  Power down on device
closure or module removal.

Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 182 ++++++++++++++++++++++++++++--
 include/linux/input/pixcir_ts.h           |  42 +++++++
 2 files changed, 216 insertions(+), 8 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a083bd..96a1b1e 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
 	const struct pixcir_ts_platform_data *chip;
-	bool exiting;
+	bool running;
 };
 
 static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
@@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 
-	while (!tsdata->exiting) {
+	while (tsdata->running) {
 		pixcir_ts_poscheck(tsdata);
 
 		if (tsdata->chip->attb_read_val())
@@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
+				 enum pixcir_power_mode mode)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_POWER_MODE_MASK;
+	ret |= mode;
+
+	/* Always AUTO_IDLE */
+	ret |= PIXCIR_POWER_ALLOW_IDLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Set the interrupt mode for the device i.e. ATTB line behaviour
+ *
+ * @polarity : 1 for active high, 0 for active low.
+ */
+static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
+			       enum pixcir_int_mode mode, bool polarity)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_INT_MODE_MASK;
+	ret |= mode;
+
+	if (polarity)
+		ret |= PIXCIR_INT_POL_HIGH;
+	else
+		ret &= ~PIXCIR_INT_POL_HIGH;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Enable/disable interrupt generation
+ */
+static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	if (enable)
+		ret |= PIXCIR_INT_ENABLE;
+	else
+		ret &= ~PIXCIR_INT_ENABLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+			__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pixcir_start(struct pixcir_i2c_ts_data *ts)
+{
+	struct device *dev = &ts->client->dev;
+	int error;
+
+	/* LEVEL_TOUCH interrupt with active low polarity */
+	error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
+	if (error) {
+		dev_err(dev, "Failed to set interrupt mode: %d\n", error);
+		return error;
+	}
+
+	ts->running = true;
+	mb();	/* Update status before IRQ can fire */
+
+	/* enable interrupt generation */
+	error = pixcir_int_enable(ts, true);
+	if (error) {
+		dev_err(dev, "Failed to enable interrupt generation: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
+{
+	int error;
+
+	/* Disable interrupt generation */
+	error = pixcir_int_enable(ts, false);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"Failed to disable interrupt generation: %d\n",
+			error);
+		return error;
+	}
+
+	/* Exit ISR if running, no more report parsing */
+	ts->running = false;
+	mb();	/* update status before we synchronize irq */
+
+	/* Wait till running ISR is complete */
+	synchronize_irq(ts->client->irq);
+
+	return 0;
+}
+
+static int pixcir_input_open(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	return pixcir_start(ts);
+}
+
+static void pixcir_input_close(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	pixcir_stop(ts);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int pixcir_i2c_ts_suspend(struct device *dev)
 {
@@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
+	input->open = pixcir_input_open;
+	input->close = pixcir_input_close;
 	input->dev.parent = &client->dev;
 
 	__set_bit(EV_KEY, input->evbit);
@@ -176,11 +336,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		return error;
 	}
 
+	/* Always be in IDLE mode to save power, device supports auto wake */
+	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
+	if (error) {
+		dev_err(dev, "Failed to set IDLE mode\n");
+		return error;
+	}
+
+	/* Stop device till opened */
+	error = pixcir_stop(tsdata);
+	if (error)
+		return error;
+
 	error = input_register_device(input);
 	if (error)
 		return error;
 
-	i2c_set_clientdata(client, tsdata);
 	device_init_wakeup(&client->dev, 1);
 
 	return 0;
@@ -188,13 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 static int 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();
-
 	return 0;
 }
 
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7163d91..7942804 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -1,6 +1,48 @@
 #ifndef	_PIXCIR_I2C_TS_H
 #define	_PIXCIR_I2C_TS_H
 
+/*
+ * Register map
+ */
+#define PIXCIR_REG_POWER_MODE	51
+#define PIXCIR_REG_INT_MODE	52
+
+/*
+ * Power modes:
+ * active: max scan speed
+ * idle: lower scan speed with automatic transition to active on touch
+ * halt: datasheet says sleep but this is more like halt as the chip
+ *       clocks are cut and it can only be brought out of this mode
+ *	 using the RESET pin.
+ */
+enum pixcir_power_mode {
+	PIXCIR_POWER_ACTIVE,
+	PIXCIR_POWER_IDLE,
+	PIXCIR_POWER_HALT,
+};
+
+#define PIXCIR_POWER_MODE_MASK	0x03
+#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
+
+/*
+ * Interrupt modes:
+ * periodical: interrupt is asserted periodicaly
+ * diff coordinates: interrupt is asserted when coordinates change
+ * level on touch: interrupt level asserted during touch
+ * pulse on touch: interrupt pulse asserted druing touch
+ *
+ */
+enum pixcir_int_mode {
+	PIXCIR_INT_PERIODICAL,
+	PIXCIR_INT_DIFF_COORD,
+	PIXCIR_INT_LEVEL_TOUCH,
+	PIXCIR_INT_PULSE_TOUCH,
+};
+
+#define PIXCIR_INT_MODE_MASK	0x03
+#define PIXCIR_INT_ENABLE	(1UL << 3)
+#define PIXCIR_INT_POL_HIGH	(1UL << 2)
+
 struct pixcir_ts_platform_data {
 	int (*attb_read_val)(void);
 	int x_max;
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
  2014-05-06 11:06 ` Roger Quadros
@ 2014-05-06 11:06   ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Get rid of the attb_read_val() platform hook. Instead,
read the ATTB gpio directly from the driver.

Fail if valid ATTB gpio is not provided by patform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 16 +++++++++++++++-
 include/linux/input/pixcir_ts.h           |  2 +-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 96a1b1e..8a7da61 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/pixcir_ts.h>
+#include <linux/gpio.h>
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
@@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
+	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
 
 	while (tsdata->running) {
 		pixcir_ts_poscheck(tsdata);
 
-		if (tsdata->chip->attb_read_val())
+		if (gpio_get_value(pdata->gpio_attb))
 			break;
 
 		msleep(20);
@@ -296,6 +298,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
+	} else {
+		if (!gpio_is_valid(pdata->gpio_attb)) {
+			dev_err(dev, "Invalid gpio_attb in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -328,6 +335,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
+	error = devm_gpio_request_one(dev, pdata->gpio_attb,
+				      GPIOF_DIR_IN, "pixcir_i2c_attb");
+	if (error) {
+		dev_err(dev, "Failed to request ATTB gpio\n");
+		return error;
+	}
+
 	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
 					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 					  client->name, tsdata);
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7942804..160cf35 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -44,9 +44,9 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
 struct pixcir_ts_platform_data {
-	int (*attb_read_val)(void);
 	int x_max;
 	int y_max;
+	int gpio_attb;		/* GPIO connected to ATTB line */
 };
 
 #endif
-- 
1.8.3.2


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

* [PATCH v5 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Get rid of the attb_read_val() platform hook. Instead,
read the ATTB gpio directly from the driver.

Fail if valid ATTB gpio is not provided by patform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 16 +++++++++++++++-
 include/linux/input/pixcir_ts.h           |  2 +-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 96a1b1e..8a7da61 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/pixcir_ts.h>
+#include <linux/gpio.h>
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
@@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
+	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
 
 	while (tsdata->running) {
 		pixcir_ts_poscheck(tsdata);
 
-		if (tsdata->chip->attb_read_val())
+		if (gpio_get_value(pdata->gpio_attb))
 			break;
 
 		msleep(20);
@@ -296,6 +298,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
+	} else {
+		if (!gpio_is_valid(pdata->gpio_attb)) {
+			dev_err(dev, "Invalid gpio_attb in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -328,6 +335,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
+	error = devm_gpio_request_one(dev, pdata->gpio_attb,
+				      GPIOF_DIR_IN, "pixcir_i2c_attb");
+	if (error) {
+		dev_err(dev, "Failed to request ATTB gpio\n");
+		return error;
+	}
+
 	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
 					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 					  client->name, tsdata);
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7942804..160cf35 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -44,9 +44,9 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
 struct pixcir_ts_platform_data {
-	int (*attb_read_val)(void);
 	int x_max;
 	int y_max;
+	int gpio_attb;		/* GPIO connected to ATTB line */
 };
 
 #endif
-- 
1.8.3.2

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

* [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  2014-05-06 11:06 ` Roger Quadros
@ 2014-05-06 11:06   ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Switch to using the Type-B Multi-Touch protocol.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 31 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a7da61..1b6e4e5 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,9 +23,12 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
+#define PIXCIR_MAX_SLOTS       2
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
@@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
 	bool running;
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+struct pixcir_touch {
+	int x;
+	int y;
+};
+
+struct pixcir_report_data {
+	int num_touches;
+	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
+};
+
+static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
+			    struct pixcir_report_data *report)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 *bufptr;
 	u8 touch;
-	int ret;
+	int ret, i;
+
+	memset(report, 0, sizeof(struct pixcir_report_data));
 
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
@@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 		return;
 	}
 
-	touch = rdbuf[0];
-	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);
+	touch = rdbuf[0] & 0x7;
+	if (touch > PIXCIR_MAX_SLOTS)
+		touch = PIXCIR_MAX_SLOTS;
+
+	report->num_touches = touch;
+	bufptr = &rdbuf[2];
+
+	for (i = 0; i < touch; i++) {
+		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
+		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
+
+		bufptr = &bufptr[4];
 	}
+}
+
+static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
+			     struct pixcir_report_data *report)
+{
+	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
+	int slots[PIXCIR_MAX_SLOTS];
+	struct pixcir_touch *touch;
+	int n, i, slot;
+	struct device *dev = &ts->client->dev;
 
-	input_sync(tsdata->input);
+	n = report->num_touches;
+	if (n > PIXCIR_MAX_SLOTS)
+		n = PIXCIR_MAX_SLOTS;
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		pos[i].x = touch->x;
+		pos[i].y = touch->y;
+	}
+
+	input_mt_assign_slots(ts->input, slots, pos, n);
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		slot = slots[i];
+
+		input_mt_slot(ts->input, slot);
+		input_mt_report_slot_state(ts->input,
+					   MT_TOOL_FINGER, true);
+
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
+
+		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
+			i, slot, touch->x, touch->y);
+	}
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
 }
 
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	struct pixcir_report_data report;
 
 	while (tsdata->running) {
-		pixcir_ts_poscheck(tsdata);
-
-		if (gpio_get_value(pdata->gpio_attb))
+		/* parse packet */
+		pixcir_ts_parse(tsdata, &report);
+
+		/* report it */
+		pixcir_ts_report(tsdata, &report);
+
+		if (gpio_get_value(pdata->gpio_attb)) {
+			if (report.num_touches) {
+				/*
+				 * Last report with no finger up?
+				 * Do it now then.
+				 */
+				input_mt_sync_frame(tsdata->input);
+				input_sync(tsdata->input);
+			}
 			break;
+		}
 
 		msleep(20);
 	}
@@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
+	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error) {
+		dev_err(dev, "Error initializing Multi-Touch slots\n");
+		return error;
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,
-- 
1.8.3.2


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

* [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Switch to using the Type-B Multi-Touch protocol.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 31 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a7da61..1b6e4e5 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,9 +23,12 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
+#define PIXCIR_MAX_SLOTS       2
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
@@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
 	bool running;
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+struct pixcir_touch {
+	int x;
+	int y;
+};
+
+struct pixcir_report_data {
+	int num_touches;
+	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
+};
+
+static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
+			    struct pixcir_report_data *report)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 *bufptr;
 	u8 touch;
-	int ret;
+	int ret, i;
+
+	memset(report, 0, sizeof(struct pixcir_report_data));
 
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
@@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 		return;
 	}
 
-	touch = rdbuf[0];
-	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);
+	touch = rdbuf[0] & 0x7;
+	if (touch > PIXCIR_MAX_SLOTS)
+		touch = PIXCIR_MAX_SLOTS;
+
+	report->num_touches = touch;
+	bufptr = &rdbuf[2];
+
+	for (i = 0; i < touch; i++) {
+		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
+		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
+
+		bufptr = &bufptr[4];
 	}
+}
+
+static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
+			     struct pixcir_report_data *report)
+{
+	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
+	int slots[PIXCIR_MAX_SLOTS];
+	struct pixcir_touch *touch;
+	int n, i, slot;
+	struct device *dev = &ts->client->dev;
 
-	input_sync(tsdata->input);
+	n = report->num_touches;
+	if (n > PIXCIR_MAX_SLOTS)
+		n = PIXCIR_MAX_SLOTS;
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		pos[i].x = touch->x;
+		pos[i].y = touch->y;
+	}
+
+	input_mt_assign_slots(ts->input, slots, pos, n);
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		slot = slots[i];
+
+		input_mt_slot(ts->input, slot);
+		input_mt_report_slot_state(ts->input,
+					   MT_TOOL_FINGER, true);
+
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
+
+		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
+			i, slot, touch->x, touch->y);
+	}
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
 }
 
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	struct pixcir_report_data report;
 
 	while (tsdata->running) {
-		pixcir_ts_poscheck(tsdata);
-
-		if (gpio_get_value(pdata->gpio_attb))
+		/* parse packet */
+		pixcir_ts_parse(tsdata, &report);
+
+		/* report it */
+		pixcir_ts_report(tsdata, &report);
+
+		if (gpio_get_value(pdata->gpio_attb)) {
+			if (report.num_touches) {
+				/*
+				 * Last report with no finger up?
+				 * Do it now then.
+				 */
+				input_mt_sync_frame(tsdata->input);
+				input_sync(tsdata->input);
+			}
 			break;
+		}
 
 		msleep(20);
 	}
@@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
+	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error) {
+		dev_err(dev, "Error initializing Multi-Touch slots\n");
+		return error;
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,
-- 
1.8.3.2


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

* [PATCH v5 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Some variants of the Pixcir touch controller support upto 5
simultaneous fingers and hardware tracking IDs. Prepare the driver
for that.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 74 ++++++++++++++++++++++++-------
 include/linux/input/pixcir_ts.h           | 12 +++++
 2 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 1b6e4e5..0728c04 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -27,18 +27,20 @@
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
-#define PIXCIR_MAX_SLOTS       2
+#define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
-	const struct pixcir_ts_platform_data *chip;
+	const struct pixcir_ts_platform_data *pdata;
 	bool running;
+	int max_fingers;	/* Max fingers supported in this instance */
 };
 
 struct pixcir_touch {
 	int x;
 	int y;
+	int id;
 };
 
 struct pixcir_report_data {
@@ -49,13 +51,21 @@ struct pixcir_report_data {
 static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 			    struct pixcir_report_data *report)
 {
-	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
+	u8 wrbuf[1] = { 0 };
 	u8 *bufptr;
 	u8 touch;
 	int ret, i;
+	int readsize;
+	const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
 
 	memset(report, 0, sizeof(struct pixcir_report_data));
 
+	i = chip->has_hw_ids ? 1 : 0;
+	readsize = 2 + tsdata->max_fingers * (4 + i);
+	if (readsize > sizeof(rdbuf))
+		readsize = sizeof(rdbuf);
+
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
 		dev_err(&tsdata->client->dev,
@@ -64,7 +74,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		return;
 	}
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+	ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
 	if (ret != sizeof(rdbuf)) {
 		dev_err(&tsdata->client->dev,
 			"%s: i2c_master_recv failed(), ret=%d\n",
@@ -73,8 +83,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 	}
 
 	touch = rdbuf[0] & 0x7;
-	if (touch > PIXCIR_MAX_SLOTS)
-		touch = PIXCIR_MAX_SLOTS;
+	if (touch > tsdata->max_fingers)
+		touch = tsdata->max_fingers;
 
 	report->num_touches = touch;
 	bufptr = &rdbuf[2];
@@ -83,7 +93,12 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
 		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
 
-		bufptr = &bufptr[4];
+		if (chip->has_hw_ids) {
+			report->touches[i].id = bufptr[4];
+			bufptr = &bufptr[5];
+		} else {
+			bufptr = &bufptr[4];
+		}
 	}
 }
 
@@ -95,22 +110,35 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 	struct pixcir_touch *touch;
 	int n, i, slot;
 	struct device *dev = &ts->client->dev;
+	const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
 
 	n = report->num_touches;
 	if (n > PIXCIR_MAX_SLOTS)
 		n = PIXCIR_MAX_SLOTS;
 
-	for (i = 0; i < n; i++) {
-		touch = &report->touches[i];
-		pos[i].x = touch->x;
-		pos[i].y = touch->y;
-	}
+	if (!chip->has_hw_ids) {
+		for (i = 0; i < n; i++) {
+			touch = &report->touches[i];
+			pos[i].x = touch->x;
+			pos[i].y = touch->y;
+		}
 
-	input_mt_assign_slots(ts->input, slots, pos, n);
+		input_mt_assign_slots(ts->input, slots, pos, n);
+	}
 
 	for (i = 0; i < n; i++) {
 		touch = &report->touches[i];
-		slot = slots[i];
+
+		if (chip->has_hw_ids) {
+			slot = input_mt_get_slot_by_key(ts->input, touch->id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n",
+					touch->id);
+				continue;
+			}
+		} else {
+			slot = slots[i];
+		}
 
 		input_mt_slot(ts->input, slot);
 		input_mt_report_slot_state(ts->input,
@@ -130,7 +158,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	struct pixcir_report_data report;
 
 	while (tsdata->running) {
@@ -359,6 +387,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 			dev_err(dev, "Invalid gpio_attb in pdata\n");
 			return -EINVAL;
 		}
+
+		if (pdata->chip.max_fingers <= 0) {
+			dev_err(dev, "Invalid max_fingers in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -373,7 +406,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	tsdata->client = client;
 	tsdata->input = input;
-	tsdata->chip = pdata;
+	tsdata->pdata = pdata;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
@@ -389,7 +422,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
-	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+	tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
+	if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
+		tsdata->max_fingers = PIXCIR_MAX_SLOTS;
+		dev_info(dev, "Limiting maximum fingers to %d\n",
+			 tsdata->max_fingers);
+	}
+
+	error = input_mt_init_slots(input, tsdata->max_fingers,
 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 	if (error) {
 		dev_err(dev, "Error initializing Multi-Touch slots\n");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 160cf35..7bae83b 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -43,10 +43,22 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_ENABLE	(1UL << 3)
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
+/**
+ * struct pixcir_irc_chip_data - chip related data
+ * @max_fingers:	Max number of fingers reported simultaneously by h/w
+ * @has_hw_ids:		Hardware supports finger tracking IDs
+ *
+ */
+struct pixcir_i2c_chip_data {
+	u8 max_fingers;
+	bool has_hw_ids;
+};
+
 struct pixcir_ts_platform_data {
 	int x_max;
 	int y_max;
 	int gpio_attb;		/* GPIO connected to ATTB line */
+	struct pixcir_i2c_chip_data chip;
 };
 
 #endif
-- 
1.8.3.2


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

* [PATCH v5 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0,
	dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0,
	nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros

Some variants of the Pixcir touch controller support upto 5
simultaneous fingers and hardware tracking IDs. Prepare the driver
for that.

Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 74 ++++++++++++++++++++++++-------
 include/linux/input/pixcir_ts.h           | 12 +++++
 2 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 1b6e4e5..0728c04 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -27,18 +27,20 @@
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
-#define PIXCIR_MAX_SLOTS       2
+#define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
-	const struct pixcir_ts_platform_data *chip;
+	const struct pixcir_ts_platform_data *pdata;
 	bool running;
+	int max_fingers;	/* Max fingers supported in this instance */
 };
 
 struct pixcir_touch {
 	int x;
 	int y;
+	int id;
 };
 
 struct pixcir_report_data {
@@ -49,13 +51,21 @@ struct pixcir_report_data {
 static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 			    struct pixcir_report_data *report)
 {
-	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
+	u8 wrbuf[1] = { 0 };
 	u8 *bufptr;
 	u8 touch;
 	int ret, i;
+	int readsize;
+	const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
 
 	memset(report, 0, sizeof(struct pixcir_report_data));
 
+	i = chip->has_hw_ids ? 1 : 0;
+	readsize = 2 + tsdata->max_fingers * (4 + i);
+	if (readsize > sizeof(rdbuf))
+		readsize = sizeof(rdbuf);
+
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
 		dev_err(&tsdata->client->dev,
@@ -64,7 +74,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		return;
 	}
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+	ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
 	if (ret != sizeof(rdbuf)) {
 		dev_err(&tsdata->client->dev,
 			"%s: i2c_master_recv failed(), ret=%d\n",
@@ -73,8 +83,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 	}
 
 	touch = rdbuf[0] & 0x7;
-	if (touch > PIXCIR_MAX_SLOTS)
-		touch = PIXCIR_MAX_SLOTS;
+	if (touch > tsdata->max_fingers)
+		touch = tsdata->max_fingers;
 
 	report->num_touches = touch;
 	bufptr = &rdbuf[2];
@@ -83,7 +93,12 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
 		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
 
-		bufptr = &bufptr[4];
+		if (chip->has_hw_ids) {
+			report->touches[i].id = bufptr[4];
+			bufptr = &bufptr[5];
+		} else {
+			bufptr = &bufptr[4];
+		}
 	}
 }
 
@@ -95,22 +110,35 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 	struct pixcir_touch *touch;
 	int n, i, slot;
 	struct device *dev = &ts->client->dev;
+	const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
 
 	n = report->num_touches;
 	if (n > PIXCIR_MAX_SLOTS)
 		n = PIXCIR_MAX_SLOTS;
 
-	for (i = 0; i < n; i++) {
-		touch = &report->touches[i];
-		pos[i].x = touch->x;
-		pos[i].y = touch->y;
-	}
+	if (!chip->has_hw_ids) {
+		for (i = 0; i < n; i++) {
+			touch = &report->touches[i];
+			pos[i].x = touch->x;
+			pos[i].y = touch->y;
+		}
 
-	input_mt_assign_slots(ts->input, slots, pos, n);
+		input_mt_assign_slots(ts->input, slots, pos, n);
+	}
 
 	for (i = 0; i < n; i++) {
 		touch = &report->touches[i];
-		slot = slots[i];
+
+		if (chip->has_hw_ids) {
+			slot = input_mt_get_slot_by_key(ts->input, touch->id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n",
+					touch->id);
+				continue;
+			}
+		} else {
+			slot = slots[i];
+		}
 
 		input_mt_slot(ts->input, slot);
 		input_mt_report_slot_state(ts->input,
@@ -130,7 +158,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	struct pixcir_report_data report;
 
 	while (tsdata->running) {
@@ -359,6 +387,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 			dev_err(dev, "Invalid gpio_attb in pdata\n");
 			return -EINVAL;
 		}
+
+		if (pdata->chip.max_fingers <= 0) {
+			dev_err(dev, "Invalid max_fingers in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -373,7 +406,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	tsdata->client = client;
 	tsdata->input = input;
-	tsdata->chip = pdata;
+	tsdata->pdata = pdata;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
@@ -389,7 +422,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
-	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+	tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
+	if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
+		tsdata->max_fingers = PIXCIR_MAX_SLOTS;
+		dev_info(dev, "Limiting maximum fingers to %d\n",
+			 tsdata->max_fingers);
+	}
+
+	error = input_mt_init_slots(input, tsdata->max_fingers,
 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 	if (error) {
 		dev_err(dev, "Error initializing Multi-Touch slots\n");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 160cf35..7bae83b 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -43,10 +43,22 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_ENABLE	(1UL << 3)
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
+/**
+ * struct pixcir_irc_chip_data - chip related data
+ * @max_fingers:	Max number of fingers reported simultaneously by h/w
+ * @has_hw_ids:		Hardware supports finger tracking IDs
+ *
+ */
+struct pixcir_i2c_chip_data {
+	u8 max_fingers;
+	bool has_hw_ids;
+};
+
 struct pixcir_ts_platform_data {
 	int x_max;
 	int y_max;
 	int gpio_attb;		/* GPIO connected to ATTB line */
+	struct pixcir_i2c_chip_data chip;
 };
 
 #endif
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend
  2014-05-06 11:06 ` Roger Quadros
@ 2014-05-06 11:06   ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Improve the suspend and resume handlers to allow the device
to wakeup the system from suspend.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 47 ++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 0728c04..b0f7680 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -348,21 +348,59 @@ static void pixcir_input_close(struct input_dev *dev)
 static int pixcir_i2c_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	if (device_may_wakeup(&client->dev)) {
+		if (!input->users) {
+			ret = pixcir_start(ts);
+			if (ret) {
+				dev_err(dev, "Failed to start\n");
+				goto unlock;
+			}
+		}
 
-	if (device_may_wakeup(&client->dev))
 		enable_irq_wake(client->irq);
+	} else if (input->users) {
+		ret = pixcir_stop(ts);
+	}
 
-	return 0;
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
 }
 
 static int pixcir_i2c_ts_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
 
-	if (device_may_wakeup(&client->dev))
+	if (device_may_wakeup(&client->dev)) {
 		disable_irq_wake(client->irq);
 
-	return 0;
+		if (!input->users) {
+			ret = pixcir_stop(ts);
+			if (ret) {
+				dev_err(dev, "Failed to stop\n");
+				goto unlock;
+			}
+		}
+	} else if (input->users) {
+		ret = pixcir_start(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
 }
 #endif
 
@@ -469,6 +507,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	if (error)
 		return error;
 
+	i2c_set_clientdata(client, tsdata);
 	device_init_wakeup(&client->dev, 1);
 
 	return 0;
-- 
1.8.3.2


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

* [PATCH v5 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Improve the suspend and resume handlers to allow the device
to wakeup the system from suspend.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 47 ++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 0728c04..b0f7680 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -348,21 +348,59 @@ static void pixcir_input_close(struct input_dev *dev)
 static int pixcir_i2c_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	if (device_may_wakeup(&client->dev)) {
+		if (!input->users) {
+			ret = pixcir_start(ts);
+			if (ret) {
+				dev_err(dev, "Failed to start\n");
+				goto unlock;
+			}
+		}
 
-	if (device_may_wakeup(&client->dev))
 		enable_irq_wake(client->irq);
+	} else if (input->users) {
+		ret = pixcir_stop(ts);
+	}
 
-	return 0;
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
 }
 
 static int pixcir_i2c_ts_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
 
-	if (device_may_wakeup(&client->dev))
+	if (device_may_wakeup(&client->dev)) {
 		disable_irq_wake(client->irq);
 
-	return 0;
+		if (!input->users) {
+			ret = pixcir_stop(ts);
+			if (ret) {
+				dev_err(dev, "Failed to stop\n");
+				goto unlock;
+			}
+		}
+	} else if (input->users) {
+		ret = pixcir_start(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
 }
 #endif
 
@@ -469,6 +507,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	if (error)
 		return error;
 
+	i2c_set_clientdata(client, tsdata);
 	device_init_wakeup(&client->dev, 1);
 
 	return 0;
-- 
1.8.3.2

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

* [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support
  2014-05-06 11:06 ` Roger Quadros
@ 2014-05-06 11:06   ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Provide device tree support and binding information.
Also provide support for a new chip "pixcir_tangoc".

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
new file mode 100644
index 0000000..0ab9505
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -0,0 +1,26 @@
+* Pixcir I2C touchscreen controllers
+
+Required properties:
+- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- attb-gpio: GPIO connected to the ATTB line of the chip
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Example:
+
+	i2c@00000000 {
+		/* ... */
+
+		pixcir_ts@5c {
+			compatible = "pixcir,pixcir_ts";
+			reg = <0x5c>;
+			interrupts = <2 0>;
+			attb-gpio = <&gpf 2 0 2>;
+			x-size = <800>;
+			y-size = <600>;
+		};
+
+		/* ... */
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..2270ebe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -94,6 +94,7 @@ panasonic	Panasonic Corporation
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
 plathome	Plat'Home Co., Ltd.
+pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 powervr	PowerVR (deprecated, use img)
 qca	Qualcomm Atheros, Inc.
 qcom	Qualcomm Technologies, Inc
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index b0f7680..a2f8100 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -26,6 +26,9 @@
 #include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
@@ -407,16 +410,70 @@ unlock:
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pixcir_of_match[];
+
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	struct pixcir_ts_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
+
+	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
+	/* gpio_attb validity is checked in probe */
+
+	if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
+		dev_err(dev, "Failed to get x-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->x_max -= 1;
+
+	if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
+		dev_err(dev, "Failed to get y-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->y_max -= 1;
+
+	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
+		pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
+
+	return pdata;
+}
+#else
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
 static int pixcir_i2c_ts_probe(struct i2c_client *client,
 					 const struct i2c_device_id *id)
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
 	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
 
+	if (np && !pdata) {
+		pdata = pixcir_parse_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
@@ -522,15 +579,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
+	{ "pixcir_tangoc", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
+#ifdef CONFIG_OF
+static const struct pixcir_i2c_chip_data pixcir_ts_data = {
+	.max_fingers = 2,
+	/* no hw id support */
+};
+
+static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
+	.max_fingers = 5,
+	.has_hw_ids = true,
+};
+
+static const struct of_device_id pixcir_of_match[] = {
+	{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
+	{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pixcir_of_match);
+#endif
+
 static struct i2c_driver pixcir_i2c_ts_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pixcir_ts",
 		.pm	= &pixcir_dev_pm_ops,
+		.of_match_table = of_match_ptr(pixcir_of_match),
 	},
 	.probe		= pixcir_i2c_ts_probe,
 	.remove		= pixcir_i2c_ts_remove,
-- 
1.8.3.2


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

* [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support
@ 2014-05-06 11:06   ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-06 11:06 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

Provide device tree support and binding information.
Also provide support for a new chip "pixcir_tangoc".

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
new file mode 100644
index 0000000..0ab9505
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -0,0 +1,26 @@
+* Pixcir I2C touchscreen controllers
+
+Required properties:
+- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- attb-gpio: GPIO connected to the ATTB line of the chip
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Example:
+
+	i2c@00000000 {
+		/* ... */
+
+		pixcir_ts@5c {
+			compatible = "pixcir,pixcir_ts";
+			reg = <0x5c>;
+			interrupts = <2 0>;
+			attb-gpio = <&gpf 2 0 2>;
+			x-size = <800>;
+			y-size = <600>;
+		};
+
+		/* ... */
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..2270ebe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -94,6 +94,7 @@ panasonic	Panasonic Corporation
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
 plathome	Plat'Home Co., Ltd.
+pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 powervr	PowerVR (deprecated, use img)
 qca	Qualcomm Atheros, Inc.
 qcom	Qualcomm Technologies, Inc
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index b0f7680..a2f8100 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -26,6 +26,9 @@
 #include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
@@ -407,16 +410,70 @@ unlock:
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pixcir_of_match[];
+
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	struct pixcir_ts_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
+
+	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
+	/* gpio_attb validity is checked in probe */
+
+	if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
+		dev_err(dev, "Failed to get x-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->x_max -= 1;
+
+	if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
+		dev_err(dev, "Failed to get y-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->y_max -= 1;
+
+	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
+		pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
+
+	return pdata;
+}
+#else
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
 static int pixcir_i2c_ts_probe(struct i2c_client *client,
 					 const struct i2c_device_id *id)
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
 	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
 
+	if (np && !pdata) {
+		pdata = pixcir_parse_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
@@ -522,15 +579,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
+	{ "pixcir_tangoc", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
+#ifdef CONFIG_OF
+static const struct pixcir_i2c_chip_data pixcir_ts_data = {
+	.max_fingers = 2,
+	/* no hw id support */
+};
+
+static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
+	.max_fingers = 5,
+	.has_hw_ids = true,
+};
+
+static const struct of_device_id pixcir_of_match[] = {
+	{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
+	{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pixcir_of_match);
+#endif
+
 static struct i2c_driver pixcir_i2c_ts_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pixcir_ts",
 		.pm	= &pixcir_dev_pm_ops,
+		.of_match_table = of_match_ptr(pixcir_of_match),
 	},
 	.probe		= pixcir_i2c_ts_probe,
 	.remove		= pixcir_i2c_ts_remove,
-- 
1.8.3.2


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

* Re: [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:54   ` Dmitry Torokhov
  2014-05-19  7:50       ` Roger Quadros
  -1 siblings, 1 reply; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:54 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:12PM +0300, Roger Quadros wrote:
> Provide device tree support and binding information.
> Also provide support for a new chip "pixcir_tangoc".
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>  drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
>  3 files changed, 105 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> new file mode 100644
> index 0000000..0ab9505
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> @@ -0,0 +1,26 @@
> +* Pixcir I2C touchscreen controllers
> +
> +Required properties:
> +- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
> +- reg: I2C address of the chip
> +- interrupts: interrupt to which the chip is connected
> +- attb-gpio: GPIO connected to the ATTB line of the chip
> +- x-size: horizontal resolution of touchscreen
> +- y-size: vertical resolution of touchscreen

There is a patch by Sebastian Reichel trying to unify touchscreen OF
properties, I think it would be nice if we used the same properties
here.

Thanks.

-- 
Dmitry

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

* Re: [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:54   ` Dmitry Torokhov
  -1 siblings, 0 replies; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:54 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:09PM +0300, Roger Quadros wrote:
> Switch to using the Type-B Multi-Touch protocol.
> 

Henrik, any chance you could take a look at MT-B support?

> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>  1 file changed, 94 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 8a7da61..1b6e4e5 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -23,9 +23,12 @@
>  #include <linux/slab.h>
>  #include <linux/i2c.h>
>  #include <linux/input.h>
> +#include <linux/input/mt.h>
>  #include <linux/input/pixcir_ts.h>
>  #include <linux/gpio.h>
>  
> +#define PIXCIR_MAX_SLOTS       2
> +
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>  	bool running;
>  };
>  
> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +struct pixcir_touch {
> +	int x;
> +	int y;
> +};
> +
> +struct pixcir_report_data {
> +	int num_touches;
> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
> +};
> +
> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
> +			    struct pixcir_report_data *report)
>  {
> -	struct pixcir_i2c_ts_data *tsdata = data;
>  	u8 rdbuf[10], wrbuf[1] = { 0 };
> +	u8 *bufptr;
>  	u8 touch;
> -	int ret;
> +	int ret, i;
> +
> +	memset(report, 0, sizeof(struct pixcir_report_data));
>  
>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>  	if (ret != sizeof(wrbuf)) {
> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>  		return;
>  	}
>  
> -	touch = rdbuf[0];
> -	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);
> +	touch = rdbuf[0] & 0x7;
> +	if (touch > PIXCIR_MAX_SLOTS)
> +		touch = PIXCIR_MAX_SLOTS;
> +
> +	report->num_touches = touch;
> +	bufptr = &rdbuf[2];
> +
> +	for (i = 0; i < touch; i++) {
> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
> +
> +		bufptr = &bufptr[4];
>  	}
> +}
> +
> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
> +			     struct pixcir_report_data *report)
> +{
> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
> +	int slots[PIXCIR_MAX_SLOTS];
> +	struct pixcir_touch *touch;
> +	int n, i, slot;
> +	struct device *dev = &ts->client->dev;
>  
> -	input_sync(tsdata->input);
> +	n = report->num_touches;
> +	if (n > PIXCIR_MAX_SLOTS)
> +		n = PIXCIR_MAX_SLOTS;
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		pos[i].x = touch->x;
> +		pos[i].y = touch->y;
> +	}
> +
> +	input_mt_assign_slots(ts->input, slots, pos, n);
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		slot = slots[i];
> +
> +		input_mt_slot(ts->input, slot);
> +		input_mt_report_slot_state(ts->input,
> +					   MT_TOOL_FINGER, true);
> +
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
> +
> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
> +			i, slot, touch->x, touch->y);
> +	}
> +
> +	input_mt_sync_frame(ts->input);
> +	input_sync(ts->input);
>  }
>  
>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
> +	struct pixcir_report_data report;
>  
>  	while (tsdata->running) {
> -		pixcir_ts_poscheck(tsdata);
> -
> -		if (gpio_get_value(pdata->gpio_attb))
> +		/* parse packet */
> +		pixcir_ts_parse(tsdata, &report);
> +
> +		/* report it */
> +		pixcir_ts_report(tsdata, &report);
> +
> +		if (gpio_get_value(pdata->gpio_attb)) {
> +			if (report.num_touches) {
> +				/*
> +				 * Last report with no finger up?
> +				 * Do it now then.
> +				 */
> +				input_mt_sync_frame(tsdata->input);
> +				input_sync(tsdata->input);
> +			}
>  			break;
> +		}
>  
>  		msleep(20);
>  	}
> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	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);
>  
> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +	if (error) {
> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
> +		return error;
> +	}
> +
>  	input_set_drvdata(input, tsdata);
>  
>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> -- 
> 1.8.3.2
> 

-- 
Dmitry

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

* Re: [PATCH v5 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:54   ` Dmitry Torokhov
  -1 siblings, 0 replies; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:54 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:06PM +0300, Roger Quadros wrote:
> Use devm_() and friends for allocating memory, input device
> and IRQ.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>

Applied, thank you.

> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 38 ++++++++++++-------------------
>  1 file changed, 15 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 02392d2..8a083bd 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -130,6 +130,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  {
>  	const struct pixcir_ts_platform_data *pdata =
>  			dev_get_platdata(&client->dev);
> +	struct device *dev = &client->dev;
>  	struct pixcir_i2c_ts_data *tsdata;
>  	struct input_dev *input;
>  	int error;
> @@ -139,12 +140,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  		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 = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
> +	if (!tsdata)
> +		return -ENOMEM;
> +
> +	input = devm_input_allocate_device(dev);
> +	if (!input) {
> +		dev_err(&client->dev, "Failed to allocate input device\n");
> +		return -ENOMEM;
>  	}
>  
>  	tsdata->client = client;
> @@ -165,29 +168,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  
>  	input_set_drvdata(input, tsdata);
>  
> -	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
> -				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> -				     client->name, tsdata);
> +	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
> +					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +					  client->name, tsdata);
>  	if (error) {
> -		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
> -		goto err_free_mem;
> +		dev_err(dev, "failed to request irq %d\n", client->irq);
> +		return error;
>  	}
>  
>  	error = input_register_device(input);
>  	if (error)
> -		goto err_free_irq;
> +		return error;
>  
>  	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 pixcir_i2c_ts_remove(struct i2c_client *client)
> @@ -198,10 +194,6 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
>  
>  	tsdata->exiting = true;
>  	mb();
> -	free_irq(client->irq, tsdata);
> -
> -	input_unregister_device(tsdata->input);
> -	kfree(tsdata);
>  
>  	return 0;
>  }
> -- 
> 1.8.3.2
> 

-- 
Dmitry

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

* Re: [PATCH v5 2/7] Input: pixcir_i2c_ts - initialize interrupt mode and power mode
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:55   ` Dmitry Torokhov
  -1 siblings, 0 replies; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:07PM +0300, Roger Quadros wrote:
> Introduce helper functions to configure power and interrupt registers.
> Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode
> on detecting finger touch.
> 
> Configure interrupt mode and polarity on start up.  Power down on device
> closure or module removal.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Applied, thank you.

> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 182 ++++++++++++++++++++++++++++--
>  include/linux/input/pixcir_ts.h           |  42 +++++++
>  2 files changed, 216 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 8a083bd..96a1b1e 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
>  	const struct pixcir_ts_platform_data *chip;
> -	bool exiting;
> +	bool running;
>  };
>  
>  static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> @@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>  
> -	while (!tsdata->exiting) {
> +	while (tsdata->running) {
>  		pixcir_ts_poscheck(tsdata);
>  
>  		if (tsdata->chip->attb_read_val())
> @@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
> +				 enum pixcir_power_mode mode)
> +{
> +	struct device *dev = &ts->client->dev;
> +	int ret;
> +
> +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_POWER_MODE, ret);
> +		return ret;
> +	}
> +
> +	ret &= ~PIXCIR_POWER_MODE_MASK;
> +	ret |= mode;
> +
> +	/* Always AUTO_IDLE */
> +	ret |= PIXCIR_POWER_ALLOW_IDLE;
> +
> +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_POWER_MODE, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Set the interrupt mode for the device i.e. ATTB line behaviour
> + *
> + * @polarity : 1 for active high, 0 for active low.
> + */
> +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
> +			       enum pixcir_int_mode mode, bool polarity)
> +{
> +	struct device *dev = &ts->client->dev;
> +	int ret;
> +
> +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_INT_MODE, ret);
> +		return ret;
> +	}
> +
> +	ret &= ~PIXCIR_INT_MODE_MASK;
> +	ret |= mode;
> +
> +	if (polarity)
> +		ret |= PIXCIR_INT_POL_HIGH;
> +	else
> +		ret &= ~PIXCIR_INT_POL_HIGH;
> +
> +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_INT_MODE, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Enable/disable interrupt generation
> + */
> +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
> +{
> +	struct device *dev = &ts->client->dev;
> +	int ret;
> +
> +	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_INT_MODE, ret);
> +		return ret;
> +	}
> +
> +	if (enable)
> +		ret |= PIXCIR_INT_ENABLE;
> +	else
> +		ret &= ~PIXCIR_INT_ENABLE;
> +
> +	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
> +	if (ret < 0) {
> +		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
> +			__func__, PIXCIR_REG_INT_MODE, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int pixcir_start(struct pixcir_i2c_ts_data *ts)
> +{
> +	struct device *dev = &ts->client->dev;
> +	int error;
> +
> +	/* LEVEL_TOUCH interrupt with active low polarity */
> +	error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
> +	if (error) {
> +		dev_err(dev, "Failed to set interrupt mode: %d\n", error);
> +		return error;
> +	}
> +
> +	ts->running = true;
> +	mb();	/* Update status before IRQ can fire */
> +
> +	/* enable interrupt generation */
> +	error = pixcir_int_enable(ts, true);
> +	if (error) {
> +		dev_err(dev, "Failed to enable interrupt generation: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	return 0;
> +}
> +
> +static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
> +{
> +	int error;
> +
> +	/* Disable interrupt generation */
> +	error = pixcir_int_enable(ts, false);
> +	if (error) {
> +		dev_err(&ts->client->dev,
> +			"Failed to disable interrupt generation: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	/* Exit ISR if running, no more report parsing */
> +	ts->running = false;
> +	mb();	/* update status before we synchronize irq */
> +
> +	/* Wait till running ISR is complete */
> +	synchronize_irq(ts->client->irq);
> +
> +	return 0;
> +}
> +
> +static int pixcir_input_open(struct input_dev *dev)
> +{
> +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
> +
> +	return pixcir_start(ts);
> +}
> +
> +static void pixcir_input_close(struct input_dev *dev)
> +{
> +	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
> +
> +	pixcir_stop(ts);
> +}
> +
>  #ifdef CONFIG_PM_SLEEP
>  static int pixcir_i2c_ts_suspend(struct device *dev)
>  {
> @@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  
>  	input->name = client->name;
>  	input->id.bustype = BUS_I2C;
> +	input->open = pixcir_input_open;
> +	input->close = pixcir_input_close;
>  	input->dev.parent = &client->dev;
>  
>  	__set_bit(EV_KEY, input->evbit);
> @@ -176,11 +336,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  		return error;
>  	}
>  
> +	/* Always be in IDLE mode to save power, device supports auto wake */
> +	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
> +	if (error) {
> +		dev_err(dev, "Failed to set IDLE mode\n");
> +		return error;
> +	}
> +
> +	/* Stop device till opened */
> +	error = pixcir_stop(tsdata);
> +	if (error)
> +		return error;
> +
>  	error = input_register_device(input);
>  	if (error)
>  		return error;
>  
> -	i2c_set_clientdata(client, tsdata);
>  	device_init_wakeup(&client->dev, 1);
>  
>  	return 0;
> @@ -188,13 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  
>  static int 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();
> -
>  	return 0;
>  }
>  
> diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
> index 7163d91..7942804 100644
> --- a/include/linux/input/pixcir_ts.h
> +++ b/include/linux/input/pixcir_ts.h
> @@ -1,6 +1,48 @@
>  #ifndef	_PIXCIR_I2C_TS_H
>  #define	_PIXCIR_I2C_TS_H
>  
> +/*
> + * Register map
> + */
> +#define PIXCIR_REG_POWER_MODE	51
> +#define PIXCIR_REG_INT_MODE	52
> +
> +/*
> + * Power modes:
> + * active: max scan speed
> + * idle: lower scan speed with automatic transition to active on touch
> + * halt: datasheet says sleep but this is more like halt as the chip
> + *       clocks are cut and it can only be brought out of this mode
> + *	 using the RESET pin.
> + */
> +enum pixcir_power_mode {
> +	PIXCIR_POWER_ACTIVE,
> +	PIXCIR_POWER_IDLE,
> +	PIXCIR_POWER_HALT,
> +};
> +
> +#define PIXCIR_POWER_MODE_MASK	0x03
> +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
> +
> +/*
> + * Interrupt modes:
> + * periodical: interrupt is asserted periodicaly
> + * diff coordinates: interrupt is asserted when coordinates change
> + * level on touch: interrupt level asserted during touch
> + * pulse on touch: interrupt pulse asserted druing touch
> + *
> + */
> +enum pixcir_int_mode {
> +	PIXCIR_INT_PERIODICAL,
> +	PIXCIR_INT_DIFF_COORD,
> +	PIXCIR_INT_LEVEL_TOUCH,
> +	PIXCIR_INT_PULSE_TOUCH,
> +};
> +
> +#define PIXCIR_INT_MODE_MASK	0x03
> +#define PIXCIR_INT_ENABLE	(1UL << 3)
> +#define PIXCIR_INT_POL_HIGH	(1UL << 2)
> +
>  struct pixcir_ts_platform_data {
>  	int (*attb_read_val)(void);
>  	int x_max;
> -- 
> 1.8.3.2
> 

-- 
Dmitry

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

* Re: [PATCH v5 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:55   ` Dmitry Torokhov
  -1 siblings, 0 replies; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:08PM +0300, Roger Quadros wrote:
> Get rid of the attb_read_val() platform hook. Instead,
> read the ATTB gpio directly from the driver.
> 
> Fail if valid ATTB gpio is not provided by patform data.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>

Applied, thank you.

> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 16 +++++++++++++++-
>  include/linux/input/pixcir_ts.h           |  2 +-
>  2 files changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 96a1b1e..8a7da61 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -24,6 +24,7 @@
>  #include <linux/i2c.h>
>  #include <linux/input.h>
>  #include <linux/input/pixcir_ts.h>
> +#include <linux/gpio.h>
>  
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
> @@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
> +	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
>  
>  	while (tsdata->running) {
>  		pixcir_ts_poscheck(tsdata);
>  
> -		if (tsdata->chip->attb_read_val())
> +		if (gpio_get_value(pdata->gpio_attb))
>  			break;
>  
>  		msleep(20);
> @@ -296,6 +298,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	if (!pdata) {
>  		dev_err(&client->dev, "platform data not defined\n");
>  		return -EINVAL;
> +	} else {
> +		if (!gpio_is_valid(pdata->gpio_attb)) {
> +			dev_err(dev, "Invalid gpio_attb in pdata\n");
> +			return -EINVAL;
> +		}
>  	}
>  
>  	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
> @@ -328,6 +335,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  
>  	input_set_drvdata(input, tsdata);
>  
> +	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> +				      GPIOF_DIR_IN, "pixcir_i2c_attb");
> +	if (error) {
> +		dev_err(dev, "Failed to request ATTB gpio\n");
> +		return error;
> +	}
> +
>  	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
>  					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
>  					  client->name, tsdata);
> diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
> index 7942804..160cf35 100644
> --- a/include/linux/input/pixcir_ts.h
> +++ b/include/linux/input/pixcir_ts.h
> @@ -44,9 +44,9 @@ enum pixcir_int_mode {
>  #define PIXCIR_INT_POL_HIGH	(1UL << 2)
>  
>  struct pixcir_ts_platform_data {
> -	int (*attb_read_val)(void);
>  	int x_max;
>  	int y_max;
> +	int gpio_attb;		/* GPIO connected to ATTB line */
>  };
>  
>  #endif
> -- 
> 1.8.3.2
> 

-- 
Dmitry

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

* Re: [PATCH v5 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend
  2014-05-06 11:06   ` Roger Quadros
  (?)
@ 2014-05-19  5:55   ` Dmitry Torokhov
  -1 siblings, 0 replies; 35+ messages in thread
From: Dmitry Torokhov @ 2014-05-19  5:55 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On Tue, May 06, 2014 at 02:06:11PM +0300, Roger Quadros wrote:
> Improve the suspend and resume handlers to allow the device
> to wakeup the system from suspend.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>

Applied, thank you.

> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 47 ++++++++++++++++++++++++++++---
>  1 file changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 0728c04..b0f7680 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -348,21 +348,59 @@ static void pixcir_input_close(struct input_dev *dev)
>  static int pixcir_i2c_ts_suspend(struct device *dev)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
> +	struct input_dev *input = ts->input;
> +	int ret = 0;
> +
> +	mutex_lock(&input->mutex);
> +
> +	if (device_may_wakeup(&client->dev)) {
> +		if (!input->users) {
> +			ret = pixcir_start(ts);
> +			if (ret) {
> +				dev_err(dev, "Failed to start\n");
> +				goto unlock;
> +			}
> +		}
>  
> -	if (device_may_wakeup(&client->dev))
>  		enable_irq_wake(client->irq);
> +	} else if (input->users) {
> +		ret = pixcir_stop(ts);
> +	}
>  
> -	return 0;
> +unlock:
> +	mutex_unlock(&input->mutex);
> +
> +	return ret;
>  }
>  
>  static int pixcir_i2c_ts_resume(struct device *dev)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> +	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
> +	struct input_dev *input = ts->input;
> +	int ret = 0;
> +
> +	mutex_lock(&input->mutex);
>  
> -	if (device_may_wakeup(&client->dev))
> +	if (device_may_wakeup(&client->dev)) {
>  		disable_irq_wake(client->irq);
>  
> -	return 0;
> +		if (!input->users) {
> +			ret = pixcir_stop(ts);
> +			if (ret) {
> +				dev_err(dev, "Failed to stop\n");
> +				goto unlock;
> +			}
> +		}
> +	} else if (input->users) {
> +		ret = pixcir_start(ts);
> +	}
> +
> +unlock:
> +	mutex_unlock(&input->mutex);
> +
> +	return ret;
>  }
>  #endif
>  
> @@ -469,6 +507,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	if (error)
>  		return error;
>  
> +	i2c_set_clientdata(client, tsdata);
>  	device_init_wakeup(&client->dev, 1);
>  
>  	return 0;
> -- 
> 1.8.3.2
> 

-- 
Dmitry

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

* Re: [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  2014-05-06 11:06   ` Roger Quadros
  (?)
  (?)
@ 2014-05-19  7:04   ` Henrik Rydberg
  2014-05-19  7:42       ` Roger Quadros
  -1 siblings, 1 reply; 35+ messages in thread
From: Henrik Rydberg @ 2014-05-19  7:04 UTC (permalink / raw)
  To: Roger Quadros, dmitry.torokhov
  Cc: balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel,
	devicetree

Hi Roger,

Thanks for the patch series. I think the patch looks great in general. Please
see some minor comments below.

On 05/06/2014 01:06 PM, Roger Quadros wrote:
> Switch to using the Type-B Multi-Touch protocol.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>  1 file changed, 94 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 8a7da61..1b6e4e5 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -23,9 +23,12 @@
>  #include <linux/slab.h>
>  #include <linux/i2c.h>
>  #include <linux/input.h>
> +#include <linux/input/mt.h>
>  #include <linux/input/pixcir_ts.h>
>  #include <linux/gpio.h>
>  
> +#define PIXCIR_MAX_SLOTS       2
> +
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>  	bool running;
>  };
>  
> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +struct pixcir_touch {
> +	int x;
> +	int y;
> +};
> +
> +struct pixcir_report_data {
> +	int num_touches;
> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
> +};
> +
> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
> +			    struct pixcir_report_data *report)
>  {
> -	struct pixcir_i2c_ts_data *tsdata = data;
>  	u8 rdbuf[10], wrbuf[1] = { 0 };
> +	u8 *bufptr;
>  	u8 touch;
> -	int ret;
> +	int ret, i;
> +
> +	memset(report, 0, sizeof(struct pixcir_report_data));
>  
>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>  	if (ret != sizeof(wrbuf)) {
> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>  		return;
>  	}
>  
> -	touch = rdbuf[0];
> -	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);
> +	touch = rdbuf[0] & 0x7;
> +	if (touch > PIXCIR_MAX_SLOTS)
> +		touch = PIXCIR_MAX_SLOTS;
> +
> +	report->num_touches = touch;
> +	bufptr = &rdbuf[2];
> +
> +	for (i = 0; i < touch; i++) {
> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
> +
> +		bufptr = &bufptr[4];
>  	}
> +}

In many places, the '&ptr[index]' form makes a lot of sense, but here, it would
have been clearer to use 'bufptr += 4'.

> +
> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
> +			     struct pixcir_report_data *report)
> +{
> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
> +	int slots[PIXCIR_MAX_SLOTS];
> +	struct pixcir_touch *touch;
> +	int n, i, slot;
> +	struct device *dev = &ts->client->dev;
>  
> -	input_sync(tsdata->input);
> +	n = report->num_touches;
> +	if (n > PIXCIR_MAX_SLOTS)
> +		n = PIXCIR_MAX_SLOTS;
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		pos[i].x = touch->x;
> +		pos[i].y = touch->y;
> +	}
> +
> +	input_mt_assign_slots(ts->input, slots, pos, n);
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		slot = slots[i];
> +
> +		input_mt_slot(ts->input, slot);
> +		input_mt_report_slot_state(ts->input,
> +					   MT_TOOL_FINGER, true);
> +
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
> +
> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
> +			i, slot, touch->x, touch->y);
> +	}
> +
> +	input_mt_sync_frame(ts->input);
> +	input_sync(ts->input);
>  }
>  
>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
> +	struct pixcir_report_data report;
>  
>  	while (tsdata->running) {
> -		pixcir_ts_poscheck(tsdata);
> -
> -		if (gpio_get_value(pdata->gpio_attb))
> +		/* parse packet */
> +		pixcir_ts_parse(tsdata, &report);
> +
> +		/* report it */
> +		pixcir_ts_report(tsdata, &report);
> +
> +		if (gpio_get_value(pdata->gpio_attb)) {
> +			if (report.num_touches) {
> +				/*
> +				 * Last report with no finger up?
> +				 * Do it now then.
> +				 */
> +				input_mt_sync_frame(tsdata->input);
> +				input_sync(tsdata->input);

I think this construct is alright for this particular patch. If anything, it
points at a need for a better model of interrupted contacts in the core.

> +			}
>  			break;
> +		}
>  
>  		msleep(20);
>  	}
> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	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);
>  
> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +	if (error) {
> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
> +		return error;
> +	}
> +
>  	input_set_drvdata(input, tsdata);
>  
>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> 

    Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks,
Henrik

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

* Re: [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-05-19  7:42       ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  7:42 UTC (permalink / raw)
  To: Henrik Rydberg, dmitry.torokhov
  Cc: balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel,
	devicetree

Hi Henrik,

On 05/19/2014 10:04 AM, Henrik Rydberg wrote:
> Hi Roger,
> 
> Thanks for the patch series. I think the patch looks great in general. Please
> see some minor comments below.
> 
> On 05/06/2014 01:06 PM, Roger Quadros wrote:
>> Switch to using the Type-B Multi-Touch protocol.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>>  1 file changed, 94 insertions(+), 31 deletions(-)
>>
>> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> index 8a7da61..1b6e4e5 100644
>> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
>> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> @@ -23,9 +23,12 @@
>>  #include <linux/slab.h>
>>  #include <linux/i2c.h>
>>  #include <linux/input.h>
>> +#include <linux/input/mt.h>
>>  #include <linux/input/pixcir_ts.h>
>>  #include <linux/gpio.h>
>>  
>> +#define PIXCIR_MAX_SLOTS       2
>> +
>>  struct pixcir_i2c_ts_data {
>>  	struct i2c_client *client;
>>  	struct input_dev *input;
>> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>>  	bool running;
>>  };
>>  
>> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>> +struct pixcir_touch {
>> +	int x;
>> +	int y;
>> +};
>> +
>> +struct pixcir_report_data {
>> +	int num_touches;
>> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
>> +};
>> +
>> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
>> +			    struct pixcir_report_data *report)
>>  {
>> -	struct pixcir_i2c_ts_data *tsdata = data;
>>  	u8 rdbuf[10], wrbuf[1] = { 0 };
>> +	u8 *bufptr;
>>  	u8 touch;
>> -	int ret;
>> +	int ret, i;
>> +
>> +	memset(report, 0, sizeof(struct pixcir_report_data));
>>  
>>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>>  	if (ret != sizeof(wrbuf)) {
>> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>>  		return;
>>  	}
>>  
>> -	touch = rdbuf[0];
>> -	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);
>> +	touch = rdbuf[0] & 0x7;
>> +	if (touch > PIXCIR_MAX_SLOTS)
>> +		touch = PIXCIR_MAX_SLOTS;
>> +
>> +	report->num_touches = touch;
>> +	bufptr = &rdbuf[2];
>> +
>> +	for (i = 0; i < touch; i++) {
>> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
>> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
>> +
>> +		bufptr = &bufptr[4];
>>  	}
>> +}
> 
> In many places, the '&ptr[index]' form makes a lot of sense, but here, it would
> have been clearer to use 'bufptr += 4'.

Agreed. I'll update it.

> 
>> +
>> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
>> +			     struct pixcir_report_data *report)
>> +{
>> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
>> +	int slots[PIXCIR_MAX_SLOTS];
>> +	struct pixcir_touch *touch;
>> +	int n, i, slot;
>> +	struct device *dev = &ts->client->dev;
>>  
>> -	input_sync(tsdata->input);
>> +	n = report->num_touches;
>> +	if (n > PIXCIR_MAX_SLOTS)
>> +		n = PIXCIR_MAX_SLOTS;
>> +
>> +	for (i = 0; i < n; i++) {
>> +		touch = &report->touches[i];
>> +		pos[i].x = touch->x;
>> +		pos[i].y = touch->y;
>> +	}
>> +
>> +	input_mt_assign_slots(ts->input, slots, pos, n);
>> +
>> +	for (i = 0; i < n; i++) {
>> +		touch = &report->touches[i];
>> +		slot = slots[i];
>> +
>> +		input_mt_slot(ts->input, slot);
>> +		input_mt_report_slot_state(ts->input,
>> +					   MT_TOOL_FINGER, true);
>> +
>> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
>> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
>> +
>> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
>> +			i, slot, touch->x, touch->y);
>> +	}
>> +
>> +	input_mt_sync_frame(ts->input);
>> +	input_sync(ts->input);
>>  }
>>  
>>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>>  {
>>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
>> +	struct pixcir_report_data report;
>>  
>>  	while (tsdata->running) {
>> -		pixcir_ts_poscheck(tsdata);
>> -
>> -		if (gpio_get_value(pdata->gpio_attb))
>> +		/* parse packet */
>> +		pixcir_ts_parse(tsdata, &report);
>> +
>> +		/* report it */
>> +		pixcir_ts_report(tsdata, &report);
>> +
>> +		if (gpio_get_value(pdata->gpio_attb)) {
>> +			if (report.num_touches) {
>> +				/*
>> +				 * Last report with no finger up?
>> +				 * Do it now then.
>> +				 */
>> +				input_mt_sync_frame(tsdata->input);
>> +				input_sync(tsdata->input);
> 
> I think this construct is alright for this particular patch. If anything, it
> points at a need for a better model of interrupted contacts in the core.

OK. 

> 
>> +			}
>>  			break;
>> +		}
>>  
>>  		msleep(20);
>>  	}
>> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>>  	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);
>>  
>> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
>> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
>> +	if (error) {
>> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
>> +		return error;
>> +	}
>> +
>>  	input_set_drvdata(input, tsdata);
>>  
>>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
>>
> 
>     Reviewed-by: Henrik Rydberg <rydberg@euromail.se>

Thanks for the review.

cheers,
-roger


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

* Re: [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-05-19  7:42       ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  7:42 UTC (permalink / raw)
  To: Henrik Rydberg, dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0,
	nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Henrik,

On 05/19/2014 10:04 AM, Henrik Rydberg wrote:
> Hi Roger,
> 
> Thanks for the patch series. I think the patch looks great in general. Please
> see some minor comments below.
> 
> On 05/06/2014 01:06 PM, Roger Quadros wrote:
>> Switch to using the Type-B Multi-Touch protocol.
>>
>> Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
>> ---
>>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>>  1 file changed, 94 insertions(+), 31 deletions(-)
>>
>> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> index 8a7da61..1b6e4e5 100644
>> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
>> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> @@ -23,9 +23,12 @@
>>  #include <linux/slab.h>
>>  #include <linux/i2c.h>
>>  #include <linux/input.h>
>> +#include <linux/input/mt.h>
>>  #include <linux/input/pixcir_ts.h>
>>  #include <linux/gpio.h>
>>  
>> +#define PIXCIR_MAX_SLOTS       2
>> +
>>  struct pixcir_i2c_ts_data {
>>  	struct i2c_client *client;
>>  	struct input_dev *input;
>> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>>  	bool running;
>>  };
>>  
>> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>> +struct pixcir_touch {
>> +	int x;
>> +	int y;
>> +};
>> +
>> +struct pixcir_report_data {
>> +	int num_touches;
>> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
>> +};
>> +
>> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
>> +			    struct pixcir_report_data *report)
>>  {
>> -	struct pixcir_i2c_ts_data *tsdata = data;
>>  	u8 rdbuf[10], wrbuf[1] = { 0 };
>> +	u8 *bufptr;
>>  	u8 touch;
>> -	int ret;
>> +	int ret, i;
>> +
>> +	memset(report, 0, sizeof(struct pixcir_report_data));
>>  
>>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>>  	if (ret != sizeof(wrbuf)) {
>> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>>  		return;
>>  	}
>>  
>> -	touch = rdbuf[0];
>> -	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);
>> +	touch = rdbuf[0] & 0x7;
>> +	if (touch > PIXCIR_MAX_SLOTS)
>> +		touch = PIXCIR_MAX_SLOTS;
>> +
>> +	report->num_touches = touch;
>> +	bufptr = &rdbuf[2];
>> +
>> +	for (i = 0; i < touch; i++) {
>> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
>> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
>> +
>> +		bufptr = &bufptr[4];
>>  	}
>> +}
> 
> In many places, the '&ptr[index]' form makes a lot of sense, but here, it would
> have been clearer to use 'bufptr += 4'.

Agreed. I'll update it.

> 
>> +
>> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
>> +			     struct pixcir_report_data *report)
>> +{
>> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
>> +	int slots[PIXCIR_MAX_SLOTS];
>> +	struct pixcir_touch *touch;
>> +	int n, i, slot;
>> +	struct device *dev = &ts->client->dev;
>>  
>> -	input_sync(tsdata->input);
>> +	n = report->num_touches;
>> +	if (n > PIXCIR_MAX_SLOTS)
>> +		n = PIXCIR_MAX_SLOTS;
>> +
>> +	for (i = 0; i < n; i++) {
>> +		touch = &report->touches[i];
>> +		pos[i].x = touch->x;
>> +		pos[i].y = touch->y;
>> +	}
>> +
>> +	input_mt_assign_slots(ts->input, slots, pos, n);
>> +
>> +	for (i = 0; i < n; i++) {
>> +		touch = &report->touches[i];
>> +		slot = slots[i];
>> +
>> +		input_mt_slot(ts->input, slot);
>> +		input_mt_report_slot_state(ts->input,
>> +					   MT_TOOL_FINGER, true);
>> +
>> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
>> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
>> +
>> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
>> +			i, slot, touch->x, touch->y);
>> +	}
>> +
>> +	input_mt_sync_frame(ts->input);
>> +	input_sync(ts->input);
>>  }
>>  
>>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>>  {
>>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
>> +	struct pixcir_report_data report;
>>  
>>  	while (tsdata->running) {
>> -		pixcir_ts_poscheck(tsdata);
>> -
>> -		if (gpio_get_value(pdata->gpio_attb))
>> +		/* parse packet */
>> +		pixcir_ts_parse(tsdata, &report);
>> +
>> +		/* report it */
>> +		pixcir_ts_report(tsdata, &report);
>> +
>> +		if (gpio_get_value(pdata->gpio_attb)) {
>> +			if (report.num_touches) {
>> +				/*
>> +				 * Last report with no finger up?
>> +				 * Do it now then.
>> +				 */
>> +				input_mt_sync_frame(tsdata->input);
>> +				input_sync(tsdata->input);
> 
> I think this construct is alright for this particular patch. If anything, it
> points at a need for a better model of interrupted contacts in the core.

OK. 

> 
>> +			}
>>  			break;
>> +		}
>>  
>>  		msleep(20);
>>  	}
>> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>>  	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);
>>  
>> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
>> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
>> +	if (error) {
>> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
>> +		return error;
>> +	}
>> +
>>  	input_set_drvdata(input, tsdata);
>>  
>>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
>>
> 
>     Reviewed-by: Henrik Rydberg <rydberg-Hk7bIW8heu4wFerOooGFRg@public.gmane.org>

Thanks for the review.

cheers,
-roger

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support
  2014-05-19  5:54   ` Dmitry Torokhov
@ 2014-05-19  7:50       ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  7:50 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On 05/19/2014 08:54 AM, Dmitry Torokhov wrote:
> On Tue, May 06, 2014 at 02:06:12PM +0300, Roger Quadros wrote:
>> Provide device tree support and binding information.
>> Also provide support for a new chip "pixcir_tangoc".
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
>>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>>  drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
>>  3 files changed, 105 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>>
>> diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>> new file mode 100644
>> index 0000000..0ab9505
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>> @@ -0,0 +1,26 @@
>> +* Pixcir I2C touchscreen controllers
>> +
>> +Required properties:
>> +- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
>> +- reg: I2C address of the chip
>> +- interrupts: interrupt to which the chip is connected
>> +- attb-gpio: GPIO connected to the ATTB line of the chip
>> +- x-size: horizontal resolution of touchscreen
>> +- y-size: vertical resolution of touchscreen
> 
> There is a patch by Sebastian Reichel trying to unify touchscreen OF
> properties, I think it would be nice if we used the same properties
> here.

OK, I'll update this patch.

cheers,
-roger

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

* Re: [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support
@ 2014-05-19  7:50       ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  7:50 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

On 05/19/2014 08:54 AM, Dmitry Torokhov wrote:
> On Tue, May 06, 2014 at 02:06:12PM +0300, Roger Quadros wrote:
>> Provide device tree support and binding information.
>> Also provide support for a new chip "pixcir_tangoc".
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>>  .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
>>  .../devicetree/bindings/vendor-prefixes.txt        |  1 +
>>  drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
>>  3 files changed, 105 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>>
>> diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>> new file mode 100644
>> index 0000000..0ab9505
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
>> @@ -0,0 +1,26 @@
>> +* Pixcir I2C touchscreen controllers
>> +
>> +Required properties:
>> +- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
>> +- reg: I2C address of the chip
>> +- interrupts: interrupt to which the chip is connected
>> +- attb-gpio: GPIO connected to the ATTB line of the chip
>> +- x-size: horizontal resolution of touchscreen
>> +- y-size: vertical resolution of touchscreen
> 
> There is a patch by Sebastian Reichel trying to unify touchscreen OF
> properties, I think it would be nice if we used the same properties
> here.

OK, I'll update this patch.

cheers,
-roger

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

* [PATCH v6 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-05-19  8:24     ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:24 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

From: Roger Quadros <rogerq@ti.com>

Switch to using the Type-B Multi-Touch protocol.

Reviewed-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 31 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a7da61..627d2f5 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,9 +23,12 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
+#define PIXCIR_MAX_SLOTS       2
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
@@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
 	bool running;
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+struct pixcir_touch {
+	int x;
+	int y;
+};
+
+struct pixcir_report_data {
+	int num_touches;
+	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
+};
+
+static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
+			    struct pixcir_report_data *report)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 *bufptr;
 	u8 touch;
-	int ret;
+	int ret, i;
+
+	memset(report, 0, sizeof(struct pixcir_report_data));
 
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
@@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 		return;
 	}
 
-	touch = rdbuf[0];
-	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);
+	touch = rdbuf[0] & 0x7;
+	if (touch > PIXCIR_MAX_SLOTS)
+		touch = PIXCIR_MAX_SLOTS;
+
+	report->num_touches = touch;
+	bufptr = &rdbuf[2];
+
+	for (i = 0; i < touch; i++) {
+		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
+		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
+
+		bufptr = bufptr + 4;
 	}
+}
+
+static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
+			     struct pixcir_report_data *report)
+{
+	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
+	int slots[PIXCIR_MAX_SLOTS];
+	struct pixcir_touch *touch;
+	int n, i, slot;
+	struct device *dev = &ts->client->dev;
 
-	input_sync(tsdata->input);
+	n = report->num_touches;
+	if (n > PIXCIR_MAX_SLOTS)
+		n = PIXCIR_MAX_SLOTS;
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		pos[i].x = touch->x;
+		pos[i].y = touch->y;
+	}
+
+	input_mt_assign_slots(ts->input, slots, pos, n);
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		slot = slots[i];
+
+		input_mt_slot(ts->input, slot);
+		input_mt_report_slot_state(ts->input,
+					   MT_TOOL_FINGER, true);
+
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
+
+		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
+			i, slot, touch->x, touch->y);
+	}
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
 }
 
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	struct pixcir_report_data report;
 
 	while (tsdata->running) {
-		pixcir_ts_poscheck(tsdata);
-
-		if (gpio_get_value(pdata->gpio_attb))
+		/* parse packet */
+		pixcir_ts_parse(tsdata, &report);
+
+		/* report it */
+		pixcir_ts_report(tsdata, &report);
+
+		if (gpio_get_value(pdata->gpio_attb)) {
+			if (report.num_touches) {
+				/*
+				 * Last report with no finger up?
+				 * Do it now then.
+				 */
+				input_mt_sync_frame(tsdata->input);
+				input_sync(tsdata->input);
+			}
 			break;
+		}
 
 		msleep(20);
 	}
@@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
+	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error) {
+		dev_err(dev, "Error initializing Multi-Touch slots\n");
+		return error;
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,
-- 
1.8.3.2



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

* [PATCH v6 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-05-19  8:24     ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:24 UTC (permalink / raw)
  To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0,
	dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0,
	nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros

From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>

Switch to using the Type-B Multi-Touch protocol.

Reviewed-by: Henrik Rydberg <rydberg-Hk7bIW8heu4wFerOooGFRg@public.gmane.org>
Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 31 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 8a7da61..627d2f5 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,9 +23,12 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
+#define PIXCIR_MAX_SLOTS       2
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
@@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
 	bool running;
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+struct pixcir_touch {
+	int x;
+	int y;
+};
+
+struct pixcir_report_data {
+	int num_touches;
+	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
+};
+
+static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
+			    struct pixcir_report_data *report)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 *bufptr;
 	u8 touch;
-	int ret;
+	int ret, i;
+
+	memset(report, 0, sizeof(struct pixcir_report_data));
 
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
@@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 		return;
 	}
 
-	touch = rdbuf[0];
-	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);
+	touch = rdbuf[0] & 0x7;
+	if (touch > PIXCIR_MAX_SLOTS)
+		touch = PIXCIR_MAX_SLOTS;
+
+	report->num_touches = touch;
+	bufptr = &rdbuf[2];
+
+	for (i = 0; i < touch; i++) {
+		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
+		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
+
+		bufptr = bufptr + 4;
 	}
+}
+
+static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
+			     struct pixcir_report_data *report)
+{
+	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
+	int slots[PIXCIR_MAX_SLOTS];
+	struct pixcir_touch *touch;
+	int n, i, slot;
+	struct device *dev = &ts->client->dev;
 
-	input_sync(tsdata->input);
+	n = report->num_touches;
+	if (n > PIXCIR_MAX_SLOTS)
+		n = PIXCIR_MAX_SLOTS;
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		pos[i].x = touch->x;
+		pos[i].y = touch->y;
+	}
+
+	input_mt_assign_slots(ts->input, slots, pos, n);
+
+	for (i = 0; i < n; i++) {
+		touch = &report->touches[i];
+		slot = slots[i];
+
+		input_mt_slot(ts->input, slot);
+		input_mt_report_slot_state(ts->input,
+					   MT_TOOL_FINGER, true);
+
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
+		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
+
+		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
+			i, slot, touch->x, touch->y);
+	}
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
 }
 
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
 	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	struct pixcir_report_data report;
 
 	while (tsdata->running) {
-		pixcir_ts_poscheck(tsdata);
-
-		if (gpio_get_value(pdata->gpio_attb))
+		/* parse packet */
+		pixcir_ts_parse(tsdata, &report);
+
+		/* report it */
+		pixcir_ts_report(tsdata, &report);
+
+		if (gpio_get_value(pdata->gpio_attb)) {
+			if (report.num_touches) {
+				/*
+				 * Last report with no finger up?
+				 * Do it now then.
+				 */
+				input_mt_sync_frame(tsdata->input);
+				input_sync(tsdata->input);
+			}
 			break;
+		}
 
 		msleep(20);
 	}
@@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
+	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error) {
+		dev_err(dev, "Error initializing Multi-Touch slots\n");
+		return error;
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,
-- 
1.8.3.2


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v6 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs
  2014-05-06 11:06   ` Roger Quadros
@ 2014-05-19  8:26     ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:26 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

From: Roger Quadros <rogerq@ti.com>

Some variants of the Pixcir touch controller support upto 5
simultaneous fingers and hardware tracking IDs. Prepare the driver
for that.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 74 ++++++++++++++++++++++++-------
 include/linux/input/pixcir_ts.h           | 12 +++++
 2 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 627d2f5..8107965 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -27,18 +27,20 @@
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
-#define PIXCIR_MAX_SLOTS       2
+#define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
-	const struct pixcir_ts_platform_data *chip;
+	const struct pixcir_ts_platform_data *pdata;
 	bool running;
+	int max_fingers;	/* Max fingers supported in this instance */
 };
 
 struct pixcir_touch {
 	int x;
 	int y;
+	int id;
 };
 
 struct pixcir_report_data {
@@ -49,13 +51,21 @@ struct pixcir_report_data {
 static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 			    struct pixcir_report_data *report)
 {
-	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
+	u8 wrbuf[1] = { 0 };
 	u8 *bufptr;
 	u8 touch;
 	int ret, i;
+	int readsize;
+	const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
 
 	memset(report, 0, sizeof(struct pixcir_report_data));
 
+	i = chip->has_hw_ids ? 1 : 0;
+	readsize = 2 + tsdata->max_fingers * (4 + i);
+	if (readsize > sizeof(rdbuf))
+		readsize = sizeof(rdbuf);
+
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
 		dev_err(&tsdata->client->dev,
@@ -64,7 +74,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		return;
 	}
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+	ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
 	if (ret != sizeof(rdbuf)) {
 		dev_err(&tsdata->client->dev,
 			"%s: i2c_master_recv failed(), ret=%d\n",
@@ -73,8 +83,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 	}
 
 	touch = rdbuf[0] & 0x7;
-	if (touch > PIXCIR_MAX_SLOTS)
-		touch = PIXCIR_MAX_SLOTS;
+	if (touch > tsdata->max_fingers)
+		touch = tsdata->max_fingers;
 
 	report->num_touches = touch;
 	bufptr = &rdbuf[2];
@@ -83,7 +93,12 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
 		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
 
-		bufptr = bufptr + 4;
+		if (chip->has_hw_ids) {
+			report->touches[i].id = bufptr[4];
+			bufptr = bufptr + 5;
+		} else {
+			bufptr = bufptr + 4;
+		}
 	}
 }
 
@@ -95,22 +110,35 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 	struct pixcir_touch *touch;
 	int n, i, slot;
 	struct device *dev = &ts->client->dev;
+	const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
 
 	n = report->num_touches;
 	if (n > PIXCIR_MAX_SLOTS)
 		n = PIXCIR_MAX_SLOTS;
 
-	for (i = 0; i < n; i++) {
-		touch = &report->touches[i];
-		pos[i].x = touch->x;
-		pos[i].y = touch->y;
-	}
+	if (!chip->has_hw_ids) {
+		for (i = 0; i < n; i++) {
+			touch = &report->touches[i];
+			pos[i].x = touch->x;
+			pos[i].y = touch->y;
+		}
 
-	input_mt_assign_slots(ts->input, slots, pos, n);
+		input_mt_assign_slots(ts->input, slots, pos, n);
+	}
 
 	for (i = 0; i < n; i++) {
 		touch = &report->touches[i];
-		slot = slots[i];
+
+		if (chip->has_hw_ids) {
+			slot = input_mt_get_slot_by_key(ts->input, touch->id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n",
+					touch->id);
+				continue;
+			}
+		} else {
+			slot = slots[i];
+		}
 
 		input_mt_slot(ts->input, slot);
 		input_mt_report_slot_state(ts->input,
@@ -130,7 +158,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	struct pixcir_report_data report;
 
 	while (tsdata->running) {
@@ -359,6 +387,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 			dev_err(dev, "Invalid gpio_attb in pdata\n");
 			return -EINVAL;
 		}
+
+		if (pdata->chip.max_fingers <= 0) {
+			dev_err(dev, "Invalid max_fingers in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -373,7 +406,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	tsdata->client = client;
 	tsdata->input = input;
-	tsdata->chip = pdata;
+	tsdata->pdata = pdata;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
@@ -389,7 +422,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
-	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+	tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
+	if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
+		tsdata->max_fingers = PIXCIR_MAX_SLOTS;
+		dev_info(dev, "Limiting maximum fingers to %d\n",
+			 tsdata->max_fingers);
+	}
+
+	error = input_mt_init_slots(input, tsdata->max_fingers,
 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 	if (error) {
 		dev_err(dev, "Error initializing Multi-Touch slots\n");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 160cf35..7bae83b 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -43,10 +43,22 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_ENABLE	(1UL << 3)
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
+/**
+ * struct pixcir_irc_chip_data - chip related data
+ * @max_fingers:	Max number of fingers reported simultaneously by h/w
+ * @has_hw_ids:		Hardware supports finger tracking IDs
+ *
+ */
+struct pixcir_i2c_chip_data {
+	u8 max_fingers;
+	bool has_hw_ids;
+};
+
 struct pixcir_ts_platform_data {
 	int x_max;
 	int y_max;
 	int gpio_attb;		/* GPIO connected to ATTB line */
+	struct pixcir_i2c_chip_data chip;
 };
 
 #endif
-- 
1.8.3.2



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

* [PATCH v6 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs
@ 2014-05-19  8:26     ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:26 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

From: Roger Quadros <rogerq@ti.com>

Some variants of the Pixcir touch controller support upto 5
simultaneous fingers and hardware tracking IDs. Prepare the driver
for that.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 74 ++++++++++++++++++++++++-------
 include/linux/input/pixcir_ts.h           | 12 +++++
 2 files changed, 69 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 627d2f5..8107965 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -27,18 +27,20 @@
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 
-#define PIXCIR_MAX_SLOTS       2
+#define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
-	const struct pixcir_ts_platform_data *chip;
+	const struct pixcir_ts_platform_data *pdata;
 	bool running;
+	int max_fingers;	/* Max fingers supported in this instance */
 };
 
 struct pixcir_touch {
 	int x;
 	int y;
+	int id;
 };
 
 struct pixcir_report_data {
@@ -49,13 +51,21 @@ struct pixcir_report_data {
 static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 			    struct pixcir_report_data *report)
 {
-	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
+	u8 wrbuf[1] = { 0 };
 	u8 *bufptr;
 	u8 touch;
 	int ret, i;
+	int readsize;
+	const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
 
 	memset(report, 0, sizeof(struct pixcir_report_data));
 
+	i = chip->has_hw_ids ? 1 : 0;
+	readsize = 2 + tsdata->max_fingers * (4 + i);
+	if (readsize > sizeof(rdbuf))
+		readsize = sizeof(rdbuf);
+
 	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 	if (ret != sizeof(wrbuf)) {
 		dev_err(&tsdata->client->dev,
@@ -64,7 +74,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		return;
 	}
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+	ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
 	if (ret != sizeof(rdbuf)) {
 		dev_err(&tsdata->client->dev,
 			"%s: i2c_master_recv failed(), ret=%d\n",
@@ -73,8 +83,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 	}
 
 	touch = rdbuf[0] & 0x7;
-	if (touch > PIXCIR_MAX_SLOTS)
-		touch = PIXCIR_MAX_SLOTS;
+	if (touch > tsdata->max_fingers)
+		touch = tsdata->max_fingers;
 
 	report->num_touches = touch;
 	bufptr = &rdbuf[2];
@@ -83,7 +93,12 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
 		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
 
-		bufptr = bufptr + 4;
+		if (chip->has_hw_ids) {
+			report->touches[i].id = bufptr[4];
+			bufptr = bufptr + 5;
+		} else {
+			bufptr = bufptr + 4;
+		}
 	}
 }
 
@@ -95,22 +110,35 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 	struct pixcir_touch *touch;
 	int n, i, slot;
 	struct device *dev = &ts->client->dev;
+	const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
 
 	n = report->num_touches;
 	if (n > PIXCIR_MAX_SLOTS)
 		n = PIXCIR_MAX_SLOTS;
 
-	for (i = 0; i < n; i++) {
-		touch = &report->touches[i];
-		pos[i].x = touch->x;
-		pos[i].y = touch->y;
-	}
+	if (!chip->has_hw_ids) {
+		for (i = 0; i < n; i++) {
+			touch = &report->touches[i];
+			pos[i].x = touch->x;
+			pos[i].y = touch->y;
+		}
 
-	input_mt_assign_slots(ts->input, slots, pos, n);
+		input_mt_assign_slots(ts->input, slots, pos, n);
+	}
 
 	for (i = 0; i < n; i++) {
 		touch = &report->touches[i];
-		slot = slots[i];
+
+		if (chip->has_hw_ids) {
+			slot = input_mt_get_slot_by_key(ts->input, touch->id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n",
+					touch->id);
+				continue;
+			}
+		} else {
+			slot = slots[i];
+		}
 
 		input_mt_slot(ts->input, slot);
 		input_mt_report_slot_state(ts->input,
@@ -130,7 +158,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	struct pixcir_report_data report;
 
 	while (tsdata->running) {
@@ -359,6 +387,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 			dev_err(dev, "Invalid gpio_attb in pdata\n");
 			return -EINVAL;
 		}
+
+		if (pdata->chip.max_fingers <= 0) {
+			dev_err(dev, "Invalid max_fingers in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -373,7 +406,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	tsdata->client = client;
 	tsdata->input = input;
-	tsdata->chip = pdata;
+	tsdata->pdata = pdata;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
@@ -389,7 +422,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	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);
 
-	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
+	tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
+	if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
+		tsdata->max_fingers = PIXCIR_MAX_SLOTS;
+		dev_info(dev, "Limiting maximum fingers to %d\n",
+			 tsdata->max_fingers);
+	}
+
+	error = input_mt_init_slots(input, tsdata->max_fingers,
 				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 	if (error) {
 		dev_err(dev, "Error initializing Multi-Touch slots\n");
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 160cf35..7bae83b 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -43,10 +43,22 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_ENABLE	(1UL << 3)
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
+/**
+ * struct pixcir_irc_chip_data - chip related data
+ * @max_fingers:	Max number of fingers reported simultaneously by h/w
+ * @has_hw_ids:		Hardware supports finger tracking IDs
+ *
+ */
+struct pixcir_i2c_chip_data {
+	u8 max_fingers;
+	bool has_hw_ids;
+};
+
 struct pixcir_ts_platform_data {
 	int x_max;
 	int y_max;
 	int gpio_attb;		/* GPIO connected to ATTB line */
+	struct pixcir_i2c_chip_data chip;
 };
 
 #endif
-- 
1.8.3.2

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

* [PATCH v6 7/7] Input: pixcir_i2c_ts: Add device tree support
  2014-05-06 11:06   ` Roger Quadros
@ 2014-05-19  8:27     ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:27 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

From: Roger Quadros <rogerq@ti.com>

Provide device tree support and binding information.
Also provide support for a new chip "pixcir_tangoc".

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
new file mode 100644
index 0000000..6e55109
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -0,0 +1,26 @@
+* Pixcir I2C touchscreen controllers
+
+Required properties:
+- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- attb-gpio: GPIO connected to the ATTB line of the chip
+- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
+- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
+
+Example:
+
+	i2c@00000000 {
+		/* ... */
+
+		pixcir_ts@5c {
+			compatible = "pixcir,pixcir_ts";
+			reg = <0x5c>;
+			interrupts = <2 0>;
+			attb-gpio = <&gpf 2 0 2>;
+			touchscreen-size-x = <800>;
+			touchscreen-size-y = <600>;
+		};
+
+		/* ... */
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..2270ebe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -94,6 +94,7 @@ panasonic	Panasonic Corporation
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
 plathome	Plat'Home Co., Ltd.
+pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 powervr	PowerVR (deprecated, use img)
 qca	Qualcomm Atheros, Inc.
 qcom	Qualcomm Technologies, Inc
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 43794fb..e1eb6c8 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -26,6 +26,9 @@
 #include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
@@ -407,16 +410,70 @@ unlock:
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pixcir_of_match[];
+
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	struct pixcir_ts_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
+
+	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
+	/* gpio_attb validity is checked in probe */
+
+	if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) {
+		dev_err(dev, "Failed to get touchscreen-size-x property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->x_max -= 1;
+
+	if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) {
+		dev_err(dev, "Failed to get touchscreen-size-y property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->y_max -= 1;
+
+	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
+		pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
+
+	return pdata;
+}
+#else
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
 static int pixcir_i2c_ts_probe(struct i2c_client *client,
 					 const struct i2c_device_id *id)
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
 	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
 
+	if (np && !pdata) {
+		pdata = pixcir_parse_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
@@ -522,15 +579,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
+	{ "pixcir_tangoc", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
+#ifdef CONFIG_OF
+static const struct pixcir_i2c_chip_data pixcir_ts_data = {
+	.max_fingers = 2,
+	/* no hw id support */
+};
+
+static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
+	.max_fingers = 5,
+	.has_hw_ids = true,
+};
+
+static const struct of_device_id pixcir_of_match[] = {
+	{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
+	{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pixcir_of_match);
+#endif
+
 static struct i2c_driver pixcir_i2c_ts_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pixcir_ts",
 		.pm	= &pixcir_dev_pm_ops,
+		.of_match_table = of_match_ptr(pixcir_of_match),
 	},
 	.probe		= pixcir_i2c_ts_probe,
 	.remove		= pixcir_i2c_ts_remove,
-- 
1.8.3.2



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

* [PATCH v6 7/7] Input: pixcir_i2c_ts: Add device tree support
@ 2014-05-19  8:27     ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-05-19  8:27 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree, Roger Quadros

From: Roger Quadros <rogerq@ti.com>

Provide device tree support and binding information.
Also provide support for a new chip "pixcir_tangoc".

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 78 ++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
new file mode 100644
index 0000000..6e55109
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -0,0 +1,26 @@
+* Pixcir I2C touchscreen controllers
+
+Required properties:
+- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- attb-gpio: GPIO connected to the ATTB line of the chip
+- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
+- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
+
+Example:
+
+	i2c@00000000 {
+		/* ... */
+
+		pixcir_ts@5c {
+			compatible = "pixcir,pixcir_ts";
+			reg = <0x5c>;
+			interrupts = <2 0>;
+			attb-gpio = <&gpf 2 0 2>;
+			touchscreen-size-x = <800>;
+			touchscreen-size-y = <600>;
+		};
+
+		/* ... */
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..2270ebe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -94,6 +94,7 @@ panasonic	Panasonic Corporation
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
 plathome	Plat'Home Co., Ltd.
+pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 powervr	PowerVR (deprecated, use img)
 qca	Qualcomm Atheros, Inc.
 qcom	Qualcomm Technologies, Inc
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 43794fb..e1eb6c8 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -26,6 +26,9 @@
 #include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
@@ -407,16 +410,70 @@ unlock:
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pixcir_of_match[];
+
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	struct pixcir_ts_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
+
+	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
+	/* gpio_attb validity is checked in probe */
+
+	if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) {
+		dev_err(dev, "Failed to get touchscreen-size-x property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->x_max -= 1;
+
+	if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) {
+		dev_err(dev, "Failed to get touchscreen-size-y property\n");
+		return ERR_PTR(-EINVAL);
+	}
+	pdata->y_max -= 1;
+
+	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
+		pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
+
+	return pdata;
+}
+#else
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
 static int pixcir_i2c_ts_probe(struct i2c_client *client,
 					 const struct i2c_device_id *id)
 {
 	const struct pixcir_ts_platform_data *pdata =
 			dev_get_platdata(&client->dev);
 	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
 
+	if (np && !pdata) {
+		pdata = pixcir_parse_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
 	if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
@@ -522,15 +579,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
+	{ "pixcir_tangoc", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
+#ifdef CONFIG_OF
+static const struct pixcir_i2c_chip_data pixcir_ts_data = {
+	.max_fingers = 2,
+	/* no hw id support */
+};
+
+static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
+	.max_fingers = 5,
+	.has_hw_ids = true,
+};
+
+static const struct of_device_id pixcir_of_match[] = {
+	{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
+	{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pixcir_of_match);
+#endif
+
 static struct i2c_driver pixcir_i2c_ts_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pixcir_ts",
 		.pm	= &pixcir_dev_pm_ops,
+		.of_match_table = of_match_ptr(pixcir_of_match),
 	},
 	.probe		= pixcir_i2c_ts_probe,
 	.remove		= pixcir_i2c_ts_remove,
-- 
1.8.3.2

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

* Re: [PATCH v6 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
  2014-05-19  8:24     ` Roger Quadros
@ 2014-06-04  8:53       ` Roger Quadros
  -1 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-06-04  8:53 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

Hi Dmitry,

We're still missing patches 4, 5 and 7 for 3.16, to get device tree and type-B support.

Do you want me to send them separately?

cheers,
-roger

On 05/19/2014 11:24 AM, Roger Quadros wrote:
> From: Roger Quadros <rogerq@ti.com>
> 
> Switch to using the Type-B Multi-Touch protocol.
> 
> Reviewed-by: Henrik Rydberg <rydberg@euromail.se>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>  1 file changed, 94 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 8a7da61..627d2f5 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -23,9 +23,12 @@
>  #include <linux/slab.h>
>  #include <linux/i2c.h>
>  #include <linux/input.h>
> +#include <linux/input/mt.h>
>  #include <linux/input/pixcir_ts.h>
>  #include <linux/gpio.h>
>  
> +#define PIXCIR_MAX_SLOTS       2
> +
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>  	bool running;
>  };
>  
> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +struct pixcir_touch {
> +	int x;
> +	int y;
> +};
> +
> +struct pixcir_report_data {
> +	int num_touches;
> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
> +};
> +
> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
> +			    struct pixcir_report_data *report)
>  {
> -	struct pixcir_i2c_ts_data *tsdata = data;
>  	u8 rdbuf[10], wrbuf[1] = { 0 };
> +	u8 *bufptr;
>  	u8 touch;
> -	int ret;
> +	int ret, i;
> +
> +	memset(report, 0, sizeof(struct pixcir_report_data));
>  
>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>  	if (ret != sizeof(wrbuf)) {
> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>  		return;
>  	}
>  
> -	touch = rdbuf[0];
> -	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);
> +	touch = rdbuf[0] & 0x7;
> +	if (touch > PIXCIR_MAX_SLOTS)
> +		touch = PIXCIR_MAX_SLOTS;
> +
> +	report->num_touches = touch;
> +	bufptr = &rdbuf[2];
> +
> +	for (i = 0; i < touch; i++) {
> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
> +
> +		bufptr = bufptr + 4;
>  	}
> +}
> +
> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
> +			     struct pixcir_report_data *report)
> +{
> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
> +	int slots[PIXCIR_MAX_SLOTS];
> +	struct pixcir_touch *touch;
> +	int n, i, slot;
> +	struct device *dev = &ts->client->dev;
>  
> -	input_sync(tsdata->input);
> +	n = report->num_touches;
> +	if (n > PIXCIR_MAX_SLOTS)
> +		n = PIXCIR_MAX_SLOTS;
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		pos[i].x = touch->x;
> +		pos[i].y = touch->y;
> +	}
> +
> +	input_mt_assign_slots(ts->input, slots, pos, n);
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		slot = slots[i];
> +
> +		input_mt_slot(ts->input, slot);
> +		input_mt_report_slot_state(ts->input,
> +					   MT_TOOL_FINGER, true);
> +
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
> +
> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
> +			i, slot, touch->x, touch->y);
> +	}
> +
> +	input_mt_sync_frame(ts->input);
> +	input_sync(ts->input);
>  }
>  
>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
> +	struct pixcir_report_data report;
>  
>  	while (tsdata->running) {
> -		pixcir_ts_poscheck(tsdata);
> -
> -		if (gpio_get_value(pdata->gpio_attb))
> +		/* parse packet */
> +		pixcir_ts_parse(tsdata, &report);
> +
> +		/* report it */
> +		pixcir_ts_report(tsdata, &report);
> +
> +		if (gpio_get_value(pdata->gpio_attb)) {
> +			if (report.num_touches) {
> +				/*
> +				 * Last report with no finger up?
> +				 * Do it now then.
> +				 */
> +				input_mt_sync_frame(tsdata->input);
> +				input_sync(tsdata->input);
> +			}
>  			break;
> +		}
>  
>  		msleep(20);
>  	}
> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	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);
>  
> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +	if (error) {
> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
> +		return error;
> +	}
> +
>  	input_set_drvdata(input, tsdata);
>  
>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> 


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

* Re: [PATCH v6 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
@ 2014-06-04  8:53       ` Roger Quadros
  0 siblings, 0 replies; 35+ messages in thread
From: Roger Quadros @ 2014-06-04  8:53 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input,
	linux-kernel, devicetree

Hi Dmitry,

We're still missing patches 4, 5 and 7 for 3.16, to get device tree and type-B support.

Do you want me to send them separately?

cheers,
-roger

On 05/19/2014 11:24 AM, Roger Quadros wrote:
> From: Roger Quadros <rogerq@ti.com>
> 
> Switch to using the Type-B Multi-Touch protocol.
> 
> Reviewed-by: Henrik Rydberg <rydberg@euromail.se>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++--------
>  1 file changed, 94 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 8a7da61..627d2f5 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -23,9 +23,12 @@
>  #include <linux/slab.h>
>  #include <linux/i2c.h>
>  #include <linux/input.h>
> +#include <linux/input/mt.h>
>  #include <linux/input/pixcir_ts.h>
>  #include <linux/gpio.h>
>  
> +#define PIXCIR_MAX_SLOTS       2
> +
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
> @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data {
>  	bool running;
>  };
>  
> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +struct pixcir_touch {
> +	int x;
> +	int y;
> +};
> +
> +struct pixcir_report_data {
> +	int num_touches;
> +	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
> +};
> +
> +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
> +			    struct pixcir_report_data *report)
>  {
> -	struct pixcir_i2c_ts_data *tsdata = data;
>  	u8 rdbuf[10], wrbuf[1] = { 0 };
> +	u8 *bufptr;
>  	u8 touch;
> -	int ret;
> +	int ret, i;
> +
> +	memset(report, 0, sizeof(struct pixcir_report_data));
>  
>  	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
>  	if (ret != sizeof(wrbuf)) {
> @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>  		return;
>  	}
>  
> -	touch = rdbuf[0];
> -	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);
> +	touch = rdbuf[0] & 0x7;
> +	if (touch > PIXCIR_MAX_SLOTS)
> +		touch = PIXCIR_MAX_SLOTS;
> +
> +	report->num_touches = touch;
> +	bufptr = &rdbuf[2];
> +
> +	for (i = 0; i < touch; i++) {
> +		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
> +		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
> +
> +		bufptr = bufptr + 4;
>  	}
> +}
> +
> +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
> +			     struct pixcir_report_data *report)
> +{
> +	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
> +	int slots[PIXCIR_MAX_SLOTS];
> +	struct pixcir_touch *touch;
> +	int n, i, slot;
> +	struct device *dev = &ts->client->dev;
>  
> -	input_sync(tsdata->input);
> +	n = report->num_touches;
> +	if (n > PIXCIR_MAX_SLOTS)
> +		n = PIXCIR_MAX_SLOTS;
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		pos[i].x = touch->x;
> +		pos[i].y = touch->y;
> +	}
> +
> +	input_mt_assign_slots(ts->input, slots, pos, n);
> +
> +	for (i = 0; i < n; i++) {
> +		touch = &report->touches[i];
> +		slot = slots[i];
> +
> +		input_mt_slot(ts->input, slot);
> +		input_mt_report_slot_state(ts->input,
> +					   MT_TOOL_FINGER, true);
> +
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
> +		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
> +
> +		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
> +			i, slot, touch->x, touch->y);
> +	}
> +
> +	input_mt_sync_frame(ts->input);
> +	input_sync(ts->input);
>  }
>  
>  static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
>  {
>  	struct pixcir_i2c_ts_data *tsdata = dev_id;
>  	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
> +	struct pixcir_report_data report;
>  
>  	while (tsdata->running) {
> -		pixcir_ts_poscheck(tsdata);
> -
> -		if (gpio_get_value(pdata->gpio_attb))
> +		/* parse packet */
> +		pixcir_ts_parse(tsdata, &report);
> +
> +		/* report it */
> +		pixcir_ts_report(tsdata, &report);
> +
> +		if (gpio_get_value(pdata->gpio_attb)) {
> +			if (report.num_touches) {
> +				/*
> +				 * Last report with no finger up?
> +				 * Do it now then.
> +				 */
> +				input_mt_sync_frame(tsdata->input);
> +				input_sync(tsdata->input);
> +			}
>  			break;
> +		}
>  
>  		msleep(20);
>  	}
> @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	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);
>  
> +	error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS,
> +				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
> +	if (error) {
> +		dev_err(dev, "Error initializing Multi-Touch slots\n");
> +		return error;
> +	}
> +
>  	input_set_drvdata(input, tsdata);
>  
>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> 


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

end of thread, other threads:[~2014-06-04  8:53 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-06 11:06 [PATCH v5 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support Roger Quadros
2014-05-06 11:06 ` Roger Quadros
2014-05-06 11:06 ` [PATCH v5 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:54   ` Dmitry Torokhov
2014-05-06 11:06 ` [PATCH v5 2/7] Input: pixcir_i2c_ts - initialize interrupt mode and power mode Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:55   ` Dmitry Torokhov
2014-05-06 11:06 ` [PATCH v5 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val() Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:55   ` Dmitry Torokhov
2014-05-06 11:06 ` [PATCH v5 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:54   ` Dmitry Torokhov
2014-05-19  7:04   ` Henrik Rydberg
2014-05-19  7:42     ` Roger Quadros
2014-05-19  7:42       ` Roger Quadros
2014-05-19  8:24   ` [PATCH v6 " Roger Quadros
2014-05-19  8:24     ` Roger Quadros
2014-06-04  8:53     ` Roger Quadros
2014-06-04  8:53       ` Roger Quadros
2014-05-06 11:06 ` [PATCH v5 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  8:26   ` [PATCH v6 " Roger Quadros
2014-05-19  8:26     ` Roger Quadros
2014-05-06 11:06 ` [PATCH v5 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:55   ` Dmitry Torokhov
2014-05-06 11:06 ` [PATCH v5 7/7] Input: pixcir_i2c_ts: Add device tree support Roger Quadros
2014-05-06 11:06   ` Roger Quadros
2014-05-19  5:54   ` Dmitry Torokhov
2014-05-19  7:50     ` Roger Quadros
2014-05-19  7:50       ` Roger Quadros
2014-05-19  8:27   ` [PATCH v6 " Roger Quadros
2014-05-19  8:27     ` Roger Quadros

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.