diff mbox

[7/9] Input: pixcir_i2c_ts: Implement Type B Multi Touch reporting

Message ID 1387358480-8313-8-git-send-email-rogerq@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roger Quadros Dec. 18, 2013, 9:21 a.m. UTC
Some pixcir controllers e.g. tangoC family report finger IDs with
the co-ordinates and are more suitable for Type-B MT protocol.

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

Comments

Dmitry Torokhov Dec. 18, 2013, 2:18 p.m. UTC | #1
On Wed, Dec 18, 2013 at 02:51:18PM +0530, Roger Quadros wrote:
> Some pixcir controllers e.g. tangoC family report finger IDs with
> the co-ordinates and are more suitable for Type-B MT protocol.
> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
> ---
>  drivers/input/touchscreen/pixcir_i2c_ts.c | 202 +++++++++++++++++++++++-------
>  1 file changed, 155 insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index ff68246..9e14415 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -23,84 +23,173 @@
>  #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>
>  #include <linux/of.h>
>  #include <linux/of_gpio.h>
>  #include <linux/of_device.h>
>  
> +#define MAX_FINGERS	5	/* Maximum supported by the driver */
> +
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
>  	struct input_dev *input;
>  	const struct pixcir_ts_platform_data *pdata;
>  	bool exiting;
> +	u8 max_fingers;		/* Maximum supported by the chip */
>  };
>  
> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
> +static void pixcir_ts_typea_report(struct pixcir_i2c_ts_data *tsdata)

Hmm, I do not think we should keep Type A reports if we can do Type B.
The protocols are not new and userspace should be able to handle MT-B by
now.

>  {
> -	struct pixcir_i2c_ts_data *tsdata = data;
> +	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
>  	u8 rdbuf[10], wrbuf[1] = { 0 };
>  	u8 touch;
>  	int ret;
>  
> -	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
> -	if (ret != sizeof(wrbuf)) {
> -		dev_err(&tsdata->client->dev,
> -			"%s: i2c_master_send failed(), ret=%d\n",
> -			__func__, ret);
> -		return;
> -	}
> +	while (!tsdata->exiting) {
>  
> -	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> -	if (ret != sizeof(rdbuf)) {
> -		dev_err(&tsdata->client->dev,
> -			"%s: i2c_master_recv failed(), ret=%d\n",
> -			__func__, ret);
> -		return;
> -	}
> +		ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
> +		if (ret != sizeof(wrbuf)) {
> +			dev_err(&tsdata->client->dev,
> +				 "%s: i2c_master_send failed(), ret=%d\n",
> +				 __func__, ret);
> +			return;
> +		}
> +
> +		ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
> +		if (ret != sizeof(rdbuf)) {
> +			dev_err(&tsdata->client->dev,
> +				 "%s: i2c_master_recv failed(), ret=%d\n",
> +				 __func__, ret);
> +			return;
> +		}
>  
> -	touch = rdbuf[0];
> -	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);
> +		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);
>  		}
> -	} else {
> -		input_report_key(tsdata->input, BTN_TOUCH, 0);
> -	}
>  
> -	input_sync(tsdata->input);
> +		input_sync(tsdata->input);
> +
> +		if (gpio_get_value(pdata->gpio_attb))
> +			break;
> +
> +		msleep(20);
> +	}
>  }
>  
> -static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
> +static void pixcir_ts_typeb_report(struct pixcir_i2c_ts_data *ts)
>  {
> -	struct pixcir_i2c_ts_data *tsdata = dev_id;
> -	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
> +	const struct pixcir_ts_platform_data *pdata = ts->pdata;
> +	struct device *dev = &ts->client->dev;
> +	u8 rdbuf[32], wrbuf[1] = { 0 };
> +	u8 *bufptr;
> +	u8 num_fingers;
> +	u8 unreliable;
> +	int ret, i;
> +
> +	while (!ts->exiting) {
> +
> +		ret = i2c_master_send(ts->client, wrbuf, sizeof(wrbuf));
> +		if (ret != sizeof(wrbuf)) {
> +			dev_err(dev, "%s: i2c_master_send failed(), ret=%d\n",
> +				 __func__, ret);
> +			return;
> +		}
>  
> -	while (!tsdata->exiting) {
> -		pixcir_ts_poscheck(tsdata);
> +		ret = i2c_master_recv(ts->client, rdbuf, sizeof(rdbuf));
> +		if (ret != sizeof(rdbuf)) {
> +			dev_err(dev, "%s: i2c_master_recv failed(), ret=%d\n",
> +				 __func__, ret);
> +			return;
> +		}
> +
> +		unreliable = rdbuf[0] & 0xe0;
> +
> +		if (unreliable)
> +			goto next;	/* ignore unreliable data */
> +
> +		num_fingers = rdbuf[0] & 0x7;
> +		bufptr = &rdbuf[2];
>  
> +		if (num_fingers > ts->max_fingers) {
> +			num_fingers = ts->max_fingers;
> +			dev_dbg(dev, "limiting num_fingers to %d\n",
> +								num_fingers);
> +		}
> +
> +		for (i = 0; i < num_fingers; i++) {
> +			u8 id;
> +			unsigned int x, y;
> +			int slot;
> +
> +			id = bufptr[4];
> +			slot = input_mt_get_slot_by_key(ts->input, id);
> +			if (slot < 0) {
> +				dev_dbg(dev, "no free slot for id 0x%x\n", id);
> +				continue;
> +			}
> +
> +
> +			x = bufptr[1] << 8 | bufptr[0];
> +			y = bufptr[3] << 8 | bufptr[2];
> +
> +			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, x);
> +			input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, y);
> +
> +			bufptr = &bufptr[5];
> +			dev_dbg(dev, "%d: id 0x%x slot %d, x %d, y %d\n",
> +							i, id, slot, x, y);
> +		}
> +
> +		/* One frame is complete so sync it */
> +		input_mt_sync_frame(ts->input);
> +		input_sync(ts->input);
> +
> +next:
>  		if (gpio_get_value(pdata->gpio_attb))
>  			break;
>  
> -		msleep(20);
> +		usleep_range(2000, 5000);
>  	}
> +}
> +
> +static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
> +{
> +	struct pixcir_i2c_ts_data *tsdata = dev_id;
> +
> +	if (tsdata->input->mt)
> +		pixcir_ts_typeb_report(tsdata);
> +	else
> +		pixcir_ts_typea_report(tsdata);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -376,9 +465,9 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	input->open = pixcir_input_open;
>  	input->close = pixcir_input_close;
>  
> -	__set_bit(EV_KEY, input->evbit);
>  	__set_bit(EV_ABS, input->evbit);
>  	__set_bit(BTN_TOUCH, input->keybit);
> +
>  	input_set_abs_params(input, ABS_X,
>  					0, pdata->x_size - 1, 0, 0);
>  	input_set_abs_params(input, ABS_Y,
> @@ -388,6 +477,25 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	input_set_abs_params(input, ABS_MT_POSITION_Y,
>  					0, pdata->y_size - 1, 0, 0);
>  
> +	/* Type-B Multi-Touch support */
> +	if (pdata->chip.num_report_ids) {
> +		const struct pixcir_i2c_chip_data *chip = &pdata->chip;
> +
> +		tsdata->max_fingers = chip->num_report_ids;
> +		if (tsdata->max_fingers > MAX_FINGERS) {
> +			dev_info(dev, "Limiting maximum fingers to %d\n",
> +								MAX_FINGERS);
> +			tsdata->max_fingers = 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");
> +			return error;
> +		}
> +	}
> +
>  	input_set_drvdata(input, tsdata);
>  
>  	error = devm_gpio_request_one(dev, pdata->gpio_attb,
> -- 
> 1.8.3.2
>
Roger Quadros Dec. 19, 2013, 5:49 a.m. UTC | #2
Hi Dmitry,

On 12/18/2013 07:48 PM, Dmitry Torokhov wrote:
> On Wed, Dec 18, 2013 at 02:51:18PM +0530, Roger Quadros wrote:
>> Some pixcir controllers e.g. tangoC family report finger IDs with
>> the co-ordinates and are more suitable for Type-B MT protocol.
>>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
>> ---
>>  drivers/input/touchscreen/pixcir_i2c_ts.c | 202 +++++++++++++++++++++++-------
>>  1 file changed, 155 insertions(+), 47 deletions(-)
>>
>> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> index ff68246..9e14415 100644
>> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
>> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
>> @@ -23,84 +23,173 @@
>>  #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>
>>  #include <linux/of.h>
>>  #include <linux/of_gpio.h>
>>  #include <linux/of_device.h>
>>  
>> +#define MAX_FINGERS	5	/* Maximum supported by the driver */
>> +
>>  struct pixcir_i2c_ts_data {
>>  	struct i2c_client *client;
>>  	struct input_dev *input;
>>  	const struct pixcir_ts_platform_data *pdata;
>>  	bool exiting;
>> +	u8 max_fingers;		/* Maximum supported by the chip */
>>  };
>>  
>> -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
>> +static void pixcir_ts_typea_report(struct pixcir_i2c_ts_data *tsdata)
> 
> Hmm, I do not think we should keep Type A reports if we can do Type B.
> The protocols are not new and userspace should be able to handle MT-B by
> now.
> 

It seems the controller the original driver was written for does not report
touch ID and just reports 2 touch co-ordinates. I'm not sure how this fits into
Type B reporting model.

cheers,
-roger
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Henrik Rydberg Dec. 21, 2013, 8:02 p.m. UTC | #3
Hi Roger,

> It seems the controller the original driver was written for does not report
> touch ID and just reports 2 touch co-ordinates. I'm not sure how this fits into
> Type B reporting model.

Look in drivers/input/mouse/cypress_ps2.c for an example of how to deal with
anonymous touch coordinates.

Thanks,
Henrik

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

Patch

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index ff68246..9e14415 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,84 +23,173 @@ 
 #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>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
 
+#define MAX_FINGERS	5	/* Maximum supported by the driver */
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
 	const struct pixcir_ts_platform_data *pdata;
 	bool exiting;
+	u8 max_fingers;		/* Maximum supported by the chip */
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+static void pixcir_ts_typea_report(struct pixcir_i2c_ts_data *tsdata)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
 	u8 touch;
 	int ret;
 
-	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
-	if (ret != sizeof(wrbuf)) {
-		dev_err(&tsdata->client->dev,
-			"%s: i2c_master_send failed(), ret=%d\n",
-			__func__, ret);
-		return;
-	}
+	while (!tsdata->exiting) {
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
-	if (ret != sizeof(rdbuf)) {
-		dev_err(&tsdata->client->dev,
-			"%s: i2c_master_recv failed(), ret=%d\n",
-			__func__, ret);
-		return;
-	}
+		ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+		if (ret != sizeof(wrbuf)) {
+			dev_err(&tsdata->client->dev,
+				 "%s: i2c_master_send failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
+
+		ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+		if (ret != sizeof(rdbuf)) {
+			dev_err(&tsdata->client->dev,
+				 "%s: i2c_master_recv failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
 
-	touch = rdbuf[0];
-	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);
+		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);
 		}
-	} else {
-		input_report_key(tsdata->input, BTN_TOUCH, 0);
-	}
 
-	input_sync(tsdata->input);
+		input_sync(tsdata->input);
+
+		if (gpio_get_value(pdata->gpio_attb))
+			break;
+
+		msleep(20);
+	}
 }
 
-static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+static void pixcir_ts_typeb_report(struct pixcir_i2c_ts_data *ts)
 {
-	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
+	const struct pixcir_ts_platform_data *pdata = ts->pdata;
+	struct device *dev = &ts->client->dev;
+	u8 rdbuf[32], wrbuf[1] = { 0 };
+	u8 *bufptr;
+	u8 num_fingers;
+	u8 unreliable;
+	int ret, i;
+
+	while (!ts->exiting) {
+
+		ret = i2c_master_send(ts->client, wrbuf, sizeof(wrbuf));
+		if (ret != sizeof(wrbuf)) {
+			dev_err(dev, "%s: i2c_master_send failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
 
-	while (!tsdata->exiting) {
-		pixcir_ts_poscheck(tsdata);
+		ret = i2c_master_recv(ts->client, rdbuf, sizeof(rdbuf));
+		if (ret != sizeof(rdbuf)) {
+			dev_err(dev, "%s: i2c_master_recv failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
+
+		unreliable = rdbuf[0] & 0xe0;
+
+		if (unreliable)
+			goto next;	/* ignore unreliable data */
+
+		num_fingers = rdbuf[0] & 0x7;
+		bufptr = &rdbuf[2];
 
+		if (num_fingers > ts->max_fingers) {
+			num_fingers = ts->max_fingers;
+			dev_dbg(dev, "limiting num_fingers to %d\n",
+								num_fingers);
+		}
+
+		for (i = 0; i < num_fingers; i++) {
+			u8 id;
+			unsigned int x, y;
+			int slot;
+
+			id = bufptr[4];
+			slot = input_mt_get_slot_by_key(ts->input, id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n", id);
+				continue;
+			}
+
+
+			x = bufptr[1] << 8 | bufptr[0];
+			y = bufptr[3] << 8 | bufptr[2];
+
+			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, x);
+			input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, y);
+
+			bufptr = &bufptr[5];
+			dev_dbg(dev, "%d: id 0x%x slot %d, x %d, y %d\n",
+							i, id, slot, x, y);
+		}
+
+		/* One frame is complete so sync it */
+		input_mt_sync_frame(ts->input);
+		input_sync(ts->input);
+
+next:
 		if (gpio_get_value(pdata->gpio_attb))
 			break;
 
-		msleep(20);
+		usleep_range(2000, 5000);
 	}
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+	struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+	if (tsdata->input->mt)
+		pixcir_ts_typeb_report(tsdata);
+	else
+		pixcir_ts_typea_report(tsdata);
 
 	return IRQ_HANDLED;
 }
@@ -376,9 +465,9 @@  static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	input->open = pixcir_input_open;
 	input->close = pixcir_input_close;
 
-	__set_bit(EV_KEY, input->evbit);
 	__set_bit(EV_ABS, input->evbit);
 	__set_bit(BTN_TOUCH, input->keybit);
+
 	input_set_abs_params(input, ABS_X,
 					0, pdata->x_size - 1, 0, 0);
 	input_set_abs_params(input, ABS_Y,
@@ -388,6 +477,25 @@  static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	input_set_abs_params(input, ABS_MT_POSITION_Y,
 					0, pdata->y_size - 1, 0, 0);
 
+	/* Type-B Multi-Touch support */
+	if (pdata->chip.num_report_ids) {
+		const struct pixcir_i2c_chip_data *chip = &pdata->chip;
+
+		tsdata->max_fingers = chip->num_report_ids;
+		if (tsdata->max_fingers > MAX_FINGERS) {
+			dev_info(dev, "Limiting maximum fingers to %d\n",
+								MAX_FINGERS);
+			tsdata->max_fingers = 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");
+			return error;
+		}
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,