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@xxxxxx> > Acked-by: Mugunthan V N <mugunthanvnm@xxxxxx> > --- > 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 > -- Dmitry -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html