From 27c347d64f5e4a7e141f6bdb85bbf59e0f1dcde6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Jun 2012 16:28:48 +0530 Subject: Input: MT - fix null pointer warning Fixes the following sparse warning: drivers/input/input-mt.c:138:40: warning: Using plain integer as NULL pointer Signed-off-by: Sachin Kamat Signed-off-by: Henrik Rydberg --- drivers/input/input-mt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index f658086fbbe0..70a16c7da8cc 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -135,7 +135,7 @@ EXPORT_SYMBOL(input_mt_report_finger_count); */ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) { - struct input_mt_slot *oldest = 0; + struct input_mt_slot *oldest = NULL; int oldid = dev->trkid; int count = 0; int i; -- cgit v1.2.2 From ec02ac2b7e1ad04ab2486fe9b2fbfc3ad5178f7c Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:02 +0800 Subject: Input: atmel_mxt_ts - derive phys from i2c client adapter This allows userspace to more easily distinguish which bus a particular atmel_mxt_ts device is attached to. The resulting phys will be something like: i2c-1-0067/input0 Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 42e645062c20..b1108cae73ac 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -250,6 +250,7 @@ struct mxt_finger { struct mxt_data { struct i2c_client *client; struct input_dev *input_dev; + char phys[64]; /* device physical location */ const struct mxt_platform_data *pdata; struct mxt_object *object_table; struct mxt_info info; @@ -1106,6 +1107,10 @@ static int __devinit mxt_probe(struct i2c_client *client, } input_dev->name = "Atmel maXTouch Touchscreen"; + snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0", + client->adapter->nr, client->addr); + input_dev->phys = data->phys; + input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; input_dev->open = mxt_input_open; -- cgit v1.2.2 From c2ef9a1a248bc597f3275e8d52e8ad68416d039f Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:03 +0800 Subject: Input: atmel_mxt_ts - use client name for irq The atmel_mxt_ts driver can support multiple devices simultaneously. Use the i2c_client name instead of the driver name when requesting an interrupt to make the different interrupts distinguishable in /proc/interrupts and top. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index b1108cae73ac..8b33f3ae4eba 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1154,7 +1154,7 @@ static int __devinit mxt_probe(struct i2c_client *client, goto err_free_object; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, - pdata->irqflags, client->dev.driver->name, data); + pdata->irqflags, client->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); goto err_free_object; -- cgit v1.2.2 From e1e1658d2eeb06e09f9855bdf6edb93474eca0c0 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:04 +0800 Subject: Input: atmel_mxt_ts - detect OOM when creating mt slots Hopefully this new code path will never be used, but better safe than sorry... Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 8b33f3ae4eba..926209cba77d 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1136,7 +1136,9 @@ static int __devinit mxt_probe(struct i2c_client *client, 0, 255, 0, 0); /* For multi touch */ - input_mt_init_slots(input_dev, MXT_MAX_FINGER); + error = input_mt_init_slots(input_dev, MXT_MAX_FINGER); + if (error) + goto err_free_mem; input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, -- cgit v1.2.2 From 639900380062ecd78ee8b265ea23929c565469b4 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:05 +0800 Subject: Input: atmel_mxt_ts - warn if sysfs could not be created If sysfs entry creation fails, the driver is still usable, so don't just abort probe. Just warn and continue. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 926209cba77d..c72f595a3203 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1172,13 +1172,10 @@ static int __devinit mxt_probe(struct i2c_client *client, error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) - goto err_unregister_device; + dev_warn(&client->dev, "error creating sysfs entries.\n"); return 0; -err_unregister_device: - input_unregister_device(input_dev); - input_dev = NULL; err_free_irq: free_irq(client->irq, data); err_free_object: -- cgit v1.2.2 From 55d6867fe659f4783e57db7b2ae0bb04e4ac816e Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:06 +0800 Subject: Input: atmel_mxt_ts - don't read T5 when dumping objects T5 is the message processor object. Reading it will only have two outcomes, neither of which is particularly useful: 1) the message count decrements, and a valid message will be lost 2) an invalid message will be read (reportid == 0xff) Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index c72f595a3203..9f8dd973e5f5 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -263,7 +263,6 @@ struct mxt_data { static bool mxt_object_readable(unsigned int type) { switch (type) { - case MXT_GEN_MESSAGE_T5: case MXT_GEN_COMMAND_T6: case MXT_GEN_POWER_T7: case MXT_GEN_ACQUIRE_T8: -- cgit v1.2.2 From 9c67b789e051449d3914d683ba3604c5babc4dd9 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:07 +0800 Subject: Input: atmel_mxt_ts - use scnprintf for object sysfs entry Using scnprintf() is a cleaner way to ensure that we don't overwrite the PAGE_SIZE sysfs output buffer. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 9f8dd973e5f5..55855b8c2efd 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -904,17 +904,13 @@ static ssize_t mxt_object_show(struct device *dev, for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; - count += snprintf(buf + count, PAGE_SIZE - count, + count += scnprintf(buf + count, PAGE_SIZE - count, "Object[%d] (Type %d)\n", i + 1, object->type); - if (count >= PAGE_SIZE) - return PAGE_SIZE - 1; if (!mxt_object_readable(object->type)) { - count += snprintf(buf + count, PAGE_SIZE - count, + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); - if (count >= PAGE_SIZE) - return PAGE_SIZE - 1; continue; } @@ -924,15 +920,11 @@ static ssize_t mxt_object_show(struct device *dev, if (error) return error; - count += snprintf(buf + count, PAGE_SIZE - count, + count += scnprintf(buf + count, PAGE_SIZE - count, "\t[%2d]: %02x (%d)\n", j, val, val); - if (count >= PAGE_SIZE) - return PAGE_SIZE - 1; } - count += snprintf(buf + count, PAGE_SIZE - count, "\n"); - if (count >= PAGE_SIZE) - return PAGE_SIZE - 1; + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); } return count; -- cgit v1.2.2 From 43a91d51d3750dd9d5a6e5d14e9250a51f01f3c1 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:08 +0800 Subject: Input: atmel_mxt_ts - optimize reading objects in object sysfs entry Read each object in a single i2c transaction instead of byte-by-byte Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 35 ++++++++++++++------------------ 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 55855b8c2efd..94dd1d156a98 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -479,20 +479,6 @@ static int mxt_read_message(struct mxt_data *data, sizeof(struct mxt_message), message); } -static int mxt_read_object(struct mxt_data *data, - u8 type, u8 offset, u8 *val) -{ - struct mxt_object *object; - u16 reg; - - object = mxt_get_object(data, type); - if (!object) - return -EINVAL; - - reg = object->start_address; - return __mxt_read_reg(data->client, reg + offset, 1, val); -} - static int mxt_write_object(struct mxt_data *data, u8 type, u8 offset, u8 val) { @@ -900,7 +886,14 @@ static ssize_t mxt_object_show(struct device *dev, int i, j; int error; u8 val; + u8 *obuf; + + /* Pre-allocate buffer large enough to hold max sized object. */ + obuf = kmalloc(256, GFP_KERNEL); + if (!obuf) + return -ENOMEM; + error = 0; for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; @@ -914,20 +907,22 @@ static ssize_t mxt_object_show(struct device *dev, continue; } + error = __mxt_read_reg(data->client, object->start_address, + object->size + 1, obuf); + if (error) + break; + for (j = 0; j < object->size + 1; j++) { - error = mxt_read_object(data, - object->type, j, &val); - if (error) - return error; + val = obuf[j]; count += scnprintf(buf + count, PAGE_SIZE - count, "\t[%2d]: %02x (%d)\n", j, val, val); } - count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); } - return count; + kfree(obuf); + return error ?: count; } static int mxt_load_fw(struct device *dev, const char *fn) -- cgit v1.2.2 From 91630955cb4c9899aa4521d1459837c66c5e9c7a Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:09 +0800 Subject: Input: atmel_mxt_ts - print less overhead when dumping objects Conserve limited (PAGE_SIZE) sysfs output buffer space by only showing readable objects and not printing the object's index, which is not useful to userspace. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 94dd1d156a98..c8cfd7b3dc9e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -897,15 +897,11 @@ static ssize_t mxt_object_show(struct device *dev, for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; - count += scnprintf(buf + count, PAGE_SIZE - count, - "Object[%d] (Type %d)\n", - i + 1, object->type); - - if (!mxt_object_readable(object->type)) { - count += scnprintf(buf + count, PAGE_SIZE - count, - "\n"); + if (!mxt_object_readable(object->type)) continue; - } + + count += scnprintf(buf + count, PAGE_SIZE - count, + "T%u:\n", object->type); error = __mxt_read_reg(data->client, object->start_address, object->size + 1, obuf); -- cgit v1.2.2 From 794eb67e76118108af5280ace2be8ae4983a6a81 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:10 +0800 Subject: Input: atmel_mxt_ts - print all instances when dumping objects For objects with multiple instances, dump them all, prepending each with its "Instance #". [rydberg@euromail.se: break out mxt_show_instance()] Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 36 +++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index c8cfd7b3dc9e..ee37b0b0e0e4 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -877,6 +877,24 @@ static void mxt_calc_resolution(struct mxt_data *data) } } +static ssize_t mxt_show_instance(char *buf, int count, + struct mxt_object *object, int instance, + const u8 *val) +{ + int i; + + if (object->instances > 0) + count += scnprintf(buf + count, PAGE_SIZE - count, + "Instance %u\n", instance); + + for (i = 0; i < object->size + 1; i++) + count += scnprintf(buf + count, PAGE_SIZE - count, + "\t[%2u]: %02x (%d)\n", i, val[i], val[i]); + count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); + + return count; +} + static ssize_t mxt_object_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -885,7 +903,6 @@ static ssize_t mxt_object_show(struct device *dev, int count = 0; int i, j; int error; - u8 val; u8 *obuf; /* Pre-allocate buffer large enough to hold max sized object. */ @@ -903,20 +920,19 @@ static ssize_t mxt_object_show(struct device *dev, count += scnprintf(buf + count, PAGE_SIZE - count, "T%u:\n", object->type); - error = __mxt_read_reg(data->client, object->start_address, - object->size + 1, obuf); - if (error) - break; + for (j = 0; j < object->instances + 1; j++) { + u16 size = object->size + 1; + u16 addr = object->start_address + j * size; - for (j = 0; j < object->size + 1; j++) { - val = obuf[j]; + error = __mxt_read_reg(data->client, addr, size, obuf); + if (error) + goto done; - count += scnprintf(buf + count, PAGE_SIZE - count, - "\t[%2d]: %02x (%d)\n", j, val, val); + count = mxt_show_instance(buf, count, object, j, obuf); } - count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); } +done: kfree(obuf); return error ?: count; } -- cgit v1.2.2 From 771733e348e3df5b6283ab3b97d28577452bf09f Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:11 +0800 Subject: Input: atmel_mxt_ts - return errors from i2c layer The i2c layer can report a variety of errors, including -ENXIO for an i2c NAK. Instead of treating them all as -EIO, pass the actual i2c layer error up to the caller. However, still report as -EIO the unlikely case that a transaction was partially completed, and no error message was returned from i2c_*(). Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index ee37b0b0e0e4..a68b2279e8df 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -396,6 +396,7 @@ static int __mxt_read_reg(struct i2c_client *client, { struct i2c_msg xfer[2]; u8 buf[2]; + int ret; buf[0] = reg & 0xff; buf[1] = (reg >> 8) & 0xff; @@ -412,12 +413,17 @@ static int __mxt_read_reg(struct i2c_client *client, xfer[1].len = len; xfer[1].buf = val; - if (i2c_transfer(client->adapter, xfer, 2) != 2) { - dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); - return -EIO; + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret == 2) { + ret = 0; + } else { + if (ret >= 0) + ret = -EIO; + dev_err(&client->dev, "%s: i2c transfer failed (%d)\n", + __func__, ret); } - return 0; + return ret; } static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) @@ -428,17 +434,23 @@ static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) { u8 buf[3]; + int ret; buf[0] = reg & 0xff; buf[1] = (reg >> 8) & 0xff; buf[2] = val; - if (i2c_master_send(client, buf, 3) != 3) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; + ret = i2c_master_send(client, buf, 3); + if (ret == 3) { + ret = 0; + } else { + if (ret >= 0) + ret = -EIO; + dev_err(&client->dev, "%s: i2c send failed (%d)\n", + __func__, ret); } - return 0; + return ret; } static int mxt_read_object_table(struct i2c_client *client, -- cgit v1.2.2 From 9638ab7c9c3b352d54f4f7e80027bd6e1c0584e8 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:12 +0800 Subject: Input: atmel_mxt_ts - add variable length __mxt_write_reg The i2c bus requires 4 bytes to do a 1-byte write (1 byte i2c address + 2 byte offset + 1 byte data). By taking a length with writes, the driver can amortize transaction overhead by performing larger transactions where appropriate. This patch just sets up the new API. Later patches refactor writes to take advantage of the larger transactions. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index a68b2279e8df..dd2577b796a4 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -431,17 +431,24 @@ static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) return __mxt_read_reg(client, reg, 1, val); } -static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) +static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len, + const void *val) { - u8 buf[3]; + u8 *buf; + size_t count; int ret; + count = len + 2; + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = reg & 0xff; buf[1] = (reg >> 8) & 0xff; - buf[2] = val; + memcpy(&buf[2], val, len); - ret = i2c_master_send(client, buf, 3); - if (ret == 3) { + ret = i2c_master_send(client, buf, count); + if (ret == count) { ret = 0; } else { if (ret >= 0) @@ -450,9 +457,15 @@ static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) __func__, ret); } + kfree(buf); return ret; } +static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) +{ + return __mxt_write_reg(client, reg, 1, &val); +} + static int mxt_read_object_table(struct i2c_client *client, u16 reg, u8 *object_buf) { -- cgit v1.2.2 From cf94bc09c89c923d339c68cf89360c02578ceee3 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:13 +0800 Subject: Input: atmel_mxt_ts - optimize writing of object table entries Write each object using a single bulk i2c write transfer. Signed-off-by: Daniel Kurtz Reviewed-by: Joonyoung Shim Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dd2577b796a4..99d5210c7ae8 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -655,7 +655,8 @@ static int mxt_check_reg_init(struct mxt_data *data) struct mxt_object *object; struct device *dev = &data->client->dev; int index = 0; - int i, j, config_offset; + int i, size; + int ret; if (!pdata->config) { dev_dbg(dev, "No cfg data defined, skipping reg init\n"); @@ -668,18 +669,17 @@ static int mxt_check_reg_init(struct mxt_data *data) if (!mxt_object_writable(object->type)) continue; - for (j = 0; - j < (object->size + 1) * (object->instances + 1); - j++) { - config_offset = index + j; - if (config_offset > pdata->config_length) { - dev_err(dev, "Not enough config data!\n"); - return -EINVAL; - } - mxt_write_object(data, object->type, j, - pdata->config[config_offset]); + size = (object->size + 1) * (object->instances + 1); + if (index + size > pdata->config_length) { + dev_err(dev, "Not enough config data!\n"); + return -EINVAL; } - index += (object->size + 1) * (object->instances + 1); + + ret = __mxt_write_reg(data->client, object->start_address, + size, &pdata->config[index]); + if (ret) + return ret; + index += size; } return 0; -- cgit v1.2.2 From 23003a8496b3f8100ed215dfda438cece5745545 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:14 +0800 Subject: Input: atmel_mxt_ts - read ID information block in one i2c transaction Reading the whole info block in one i2c transaction speeds up driver probe significantly, especially on slower i2c busses. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 99d5210c7ae8..fac379146546 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -36,6 +36,7 @@ #define MXT_FW_NAME "maxtouch.fw" /* Registers */ +#define MXT_INFO 0x00 #define MXT_FAMILY_ID 0x00 #define MXT_VARIANT_ID 0x01 #define MXT_VERSION 0x02 @@ -760,32 +761,11 @@ static int mxt_get_info(struct mxt_data *data) struct i2c_client *client = data->client; struct mxt_info *info = &data->info; int error; - u8 val; - - error = mxt_read_reg(client, MXT_FAMILY_ID, &val); - if (error) - return error; - info->family_id = val; - - error = mxt_read_reg(client, MXT_VARIANT_ID, &val); - if (error) - return error; - info->variant_id = val; - - error = mxt_read_reg(client, MXT_VERSION, &val); - if (error) - return error; - info->version = val; - - error = mxt_read_reg(client, MXT_BUILD, &val); - if (error) - return error; - info->build = val; - error = mxt_read_reg(client, MXT_OBJECT_NUM, &val); + /* Read 7-byte info block starting at address 0 */ + error = __mxt_read_reg(client, MXT_INFO, sizeof(*info), info); if (error) return error; - info->object_num = val; return 0; } -- cgit v1.2.2 From e0e0269f347ce89251ecf02ec4a209136bda258e Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:15 +0800 Subject: Input: atmel_mxt_ts - update driver ID info logging Print unsigned values as '%u'. Also, parse and print the firmware version in its canonical format, as suggested by Nick Dyer. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index fac379146546..7a839d106336 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -856,12 +856,12 @@ static int mxt_initialize(struct mxt_data *data) info->matrix_ysize = val; dev_info(&client->dev, - "Family ID: %d Variant ID: %d Version: %d Build: %d\n", - info->family_id, info->variant_id, info->version, - info->build); + "Family ID: %u Variant ID: %u Major.Minor.Build: %u.%u.%02X\n", + info->family_id, info->variant_id, info->version >> 4, + info->version & 0xf, info->build); dev_info(&client->dev, - "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n", + "Matrix X Size: %u Matrix Y Size: %u Object Num: %u\n", info->matrix_xsize, info->matrix_ysize, info->object_num); -- cgit v1.2.2 From b19fc9ec241382c2155bf56f08f02066f2fb4826 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:16 +0800 Subject: Input: atmel_mxt_ts - add sysfs entries to read fw and hw version Make firmware and hardware version strings available to userspace. This is useful, for example, to allow a userspace program to implement a firwmare update policy. Change-Id: I1eddb4bbf5f3f9ae6947a8528598973ddead18cf Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 7a839d106336..f2c1fbe2556e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -882,6 +882,26 @@ static void mxt_calc_resolution(struct mxt_data *data) } } +/* Firmware Version is returned as Major.Minor.Build */ +static ssize_t mxt_fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mxt_data *data = dev_get_drvdata(dev); + struct mxt_info *info = &data->info; + return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n", + info->version >> 4, info->version & 0xf, info->build); +} + +/* Hardware Version is returned as FamilyID.VariantID */ +static ssize_t mxt_hw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mxt_data *data = dev_get_drvdata(dev); + struct mxt_info *info = &data->info; + return scnprintf(buf, PAGE_SIZE, "%u.%u\n", + info->family_id, info->variant_id); +} + static ssize_t mxt_show_instance(char *buf, int count, struct mxt_object *object, int instance, const u8 *val) @@ -1047,10 +1067,14 @@ static ssize_t mxt_update_fw_store(struct device *dev, return count; } +static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL); +static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL); static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL); static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store); static struct attribute *mxt_attrs[] = { + &dev_attr_fw_version.attr, + &dev_attr_hw_version.attr, &dev_attr_object.attr, &dev_attr_update_fw.attr, NULL -- cgit v1.2.2 From fba5bc313c44acfb3561da69526cbc1a0029cdd8 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:17 +0800 Subject: Input: atmel_mxt_ts - simplify event reporting Instead of carrying around per-finger state in the driver instance, just report each finger as it arrives to the input layer, and let the input layer (evdev) hold the event state (which it does anyway). Note: this driver does not really do MT-B properly. Each input report (a group of input events followed by a SYN_REPORT) only contains data for a single contact. When multiple fingers are present on a device, each is properly reported in its own MT_SLOT. However, there is only ever one MT_SLOT per SYN_REPORT. This is fixed in a subsequent patch. This patch was tested with an mXT224E. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 89 +++++--------------------------- 1 file changed, 13 insertions(+), 76 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f2c1fbe2556e..c37584de49ca 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -239,14 +239,6 @@ struct mxt_message { u8 message[7]; }; -struct mxt_finger { - int status; - int x; - int y; - int area; - int pressure; -}; - /* Each client has this additional data */ struct mxt_data { struct i2c_client *client; @@ -255,7 +247,6 @@ struct mxt_data { const struct mxt_platform_data *pdata; struct mxt_object *object_table; struct mxt_info info; - struct mxt_finger finger[MXT_MAX_FINGER]; unsigned int irq; unsigned int max_x; unsigned int max_y; @@ -519,75 +510,17 @@ static int mxt_write_object(struct mxt_data *data, return mxt_write_reg(data->client, reg + offset, val); } -static void mxt_input_report(struct mxt_data *data, int single_id) -{ - struct mxt_finger *finger = data->finger; - struct input_dev *input_dev = data->input_dev; - int status = finger[single_id].status; - int finger_num = 0; - int id; - - for (id = 0; id < MXT_MAX_FINGER; id++) { - if (!finger[id].status) - continue; - - input_mt_slot(input_dev, id); - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, - finger[id].status != MXT_RELEASE); - - if (finger[id].status != MXT_RELEASE) { - finger_num++; - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].area); - input_report_abs(input_dev, ABS_MT_POSITION_X, - finger[id].x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, - finger[id].y); - input_report_abs(input_dev, ABS_MT_PRESSURE, - finger[id].pressure); - } else { - finger[id].status = 0; - } - } - - input_report_key(input_dev, BTN_TOUCH, finger_num > 0); - - if (status != MXT_RELEASE) { - input_report_abs(input_dev, ABS_X, finger[single_id].x); - input_report_abs(input_dev, ABS_Y, finger[single_id].y); - input_report_abs(input_dev, - ABS_PRESSURE, finger[single_id].pressure); - } - - input_sync(input_dev); -} - static void mxt_input_touchevent(struct mxt_data *data, struct mxt_message *message, int id) { - struct mxt_finger *finger = data->finger; struct device *dev = &data->client->dev; u8 status = message->message[0]; + struct input_dev *input_dev = data->input_dev; int x; int y; int area; int pressure; - /* Check the touch is present on the screen */ - if (!(status & MXT_DETECT)) { - if (status & MXT_RELEASE) { - dev_dbg(dev, "[%d] released\n", id); - - finger[id].status = MXT_RELEASE; - mxt_input_report(data, id); - } - return; - } - - /* Check only AMP detection */ - if (!(status & (MXT_PRESS | MXT_MOVE))) - return; - x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf); y = (message->message[2] << 4) | ((message->message[3] & 0xf)); if (data->max_x < 1024) @@ -601,15 +534,19 @@ static void mxt_input_touchevent(struct mxt_data *data, dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, status & MXT_MOVE ? "moved" : "pressed", x, y, area); + input_mt_slot(input_dev, id); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, + status & MXT_DETECT); + + if (status & MXT_DETECT) { + input_report_abs(input_dev, ABS_MT_POSITION_X, x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); + } - finger[id].status = status & MXT_MOVE ? - MXT_MOVE : MXT_PRESS; - finger[id].x = x; - finger[id].y = y; - finger[id].area = area; - finger[id].pressure = pressure; - - mxt_input_report(data, id); + input_mt_report_pointer_emulation(input_dev, false); + input_sync(input_dev); } static irqreturn_t mxt_interrupt(int irq, void *dev_id) -- cgit v1.2.2 From b2e459b81b33ca17052de03b1315d8511d769507 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:18 +0800 Subject: Input: atmel_mxt_ts - add detail to touchevent debug message Update the debug message: * print inidividual status bits * print the pressure value * use '%u' for unsigned quantities Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index c37584de49ca..d6b64a0fed45 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -195,6 +195,7 @@ #define MXT_BOOT_STATUS_MASK 0x3f /* Touch status */ +#define MXT_UNGRIP (1 << 0) #define MXT_SUPPRESS (1 << 1) #define MXT_AMP (1 << 2) #define MXT_VECTOR (1 << 3) @@ -531,9 +532,19 @@ static void mxt_input_touchevent(struct mxt_data *data, area = message->message[4]; pressure = message->message[5]; - dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, - status & MXT_MOVE ? "moved" : "pressed", - x, y, area); + dev_dbg(dev, + "[%u] %c%c%c%c%c%c%c%c x: %5u y: %5u area: %3u amp: %3u\n", + id, + (status & MXT_DETECT) ? 'D' : '.', + (status & MXT_PRESS) ? 'P' : '.', + (status & MXT_RELEASE) ? 'R' : '.', + (status & MXT_MOVE) ? 'M' : '.', + (status & MXT_VECTOR) ? 'V' : '.', + (status & MXT_AMP) ? 'A' : '.', + (status & MXT_SUPPRESS) ? 'S' : '.', + (status & MXT_UNGRIP) ? 'U' : '.', + x, y, area, pressure); + input_mt_slot(input_dev, id); input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, status & MXT_DETECT); -- cgit v1.2.2 From 7d4fa100b0cc069b2d788e1d9fe086e9e057958e Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:19 +0800 Subject: Input: atmel_mxt_ts - refactor when and how object table is freed The Object Table is freed in three cases: 1) When the driver is being removed. 2) In the error path of mxt_initialize(). 3) Just after a firmware update, when a new object table is about to be read. For cases 2 & 3, the driver is not immediately unloaded, so this patch refactors these cases to use a common cleanup function. It also refactors the mxt_initialize error paths to ensure that this cleanup happens. Note: mxt_update_fw_store() does not handle errors during mxt_initialize(). A proposed fix for this is in a subsequent patchset. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d6b64a0fed45..488e3e88c3fc 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -750,6 +750,12 @@ static int mxt_get_object_table(struct mxt_data *data) return 0; } +static void mxt_free_object_table(struct mxt_data *data) +{ + kfree(data->object_table); + data->object_table = NULL; +} + static int mxt_initialize(struct mxt_data *data) { struct i2c_client *client = data->client; @@ -772,12 +778,12 @@ static int mxt_initialize(struct mxt_data *data) /* Get object table information */ error = mxt_get_object_table(data); if (error) - return error; + goto err_free_object_table; /* Check register init values */ error = mxt_check_reg_init(data); if (error) - return error; + goto err_free_object_table; mxt_handle_pdata(data); @@ -795,12 +801,12 @@ static int mxt_initialize(struct mxt_data *data) /* Update matrix size at info struct */ error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); if (error) - return error; + goto err_free_object_table; info->matrix_xsize = val; error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val); if (error) - return error; + goto err_free_object_table; info->matrix_ysize = val; dev_info(&client->dev, @@ -814,6 +820,10 @@ static int mxt_initialize(struct mxt_data *data) info->object_num); return 0; + +err_free_object_table: + mxt_free_object_table(data); + return error; } static void mxt_calc_resolution(struct mxt_data *data) @@ -1000,8 +1010,7 @@ static ssize_t mxt_update_fw_store(struct device *dev, /* Wait for reset */ msleep(MXT_FWRESET_TIME); - kfree(data->object_table); - data->object_table = NULL; + mxt_free_object_table(data); mxt_initialize(data); } @@ -1128,7 +1137,7 @@ static int __devinit mxt_probe(struct i2c_client *client, error = mxt_initialize(data); if (error) - goto err_free_object; + goto err_free_mem; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, pdata->irqflags, client->name, data); -- cgit v1.2.2 From 333e5a9a99b8bba14f1a8631218d2d1e55fd58b1 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:20 +0800 Subject: Input: atmel_mxt_ts - cache T9 reportid range when reading object table Streamline interrupt processing by caching the T9 reportid range when first reading the object table. In the process, refactor reading the object descriptor table. First, since the object_table entries are now exactly the same layout in device memory and in the driver, allocate an appropriately sized array and fetch the entire table directly into it in a single i2c transaction. Since a 6 byte table object requires 10 bytes to read, doing this dramatically reduces overhead. Note: The cached T9 reportid's are initialized to 0, which is an invalid reportid. Thus, the checks in the interrupt handler will always fail for devices that do not support the T9 object. Therefore, after doing a firmware update, the old object table is destroyed and all cached object values are reset to 0, before reading the new object table, in case the new firmware does not have the old objects. This patch tested on an MXT224E. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 76 +++++++++++++++++--------------- 1 file changed, 41 insertions(+), 35 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 488e3e88c3fc..48f3637aecaa 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -227,13 +227,10 @@ struct mxt_info { struct mxt_object { u8 type; u16 start_address; - u8 size; - u8 instances; + u8 size; /* Size of each instance - 1 */ + u8 instances; /* Number of instances - 1 */ u8 num_report_ids; - - /* to map object and message */ - u8 max_reportid; -}; +} __packed; struct mxt_message { u8 reportid; @@ -251,6 +248,10 @@ struct mxt_data { unsigned int irq; unsigned int max_x; unsigned int max_y; + + /* Cached parameters from object table */ + u8 T9_reportid_min; + u8 T9_reportid_max; }; static bool mxt_object_readable(unsigned int type) @@ -459,13 +460,6 @@ static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) return __mxt_write_reg(client, reg, 1, &val); } -static int mxt_read_object_table(struct i2c_client *client, - u16 reg, u8 *object_buf) -{ - return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE, - object_buf); -} - static struct mxt_object * mxt_get_object(struct mxt_data *data, u8 type) { @@ -564,7 +558,6 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) { struct mxt_data *data = dev_id; struct mxt_message message; - struct mxt_object *object; struct device *dev = &data->client->dev; int id; u8 reportid; @@ -579,13 +572,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) reportid = message.reportid; - /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */ - object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); - if (!object) - goto end; - - max_reportid = object->max_reportid; - min_reportid = max_reportid - object->num_report_ids + 1; + max_reportid = data->T9_reportid_max; + min_reportid = data->T9_reportid_min; id = reportid - min_reportid; if (reportid >= min_reportid && reportid <= max_reportid) @@ -720,30 +708,46 @@ static int mxt_get_info(struct mxt_data *data) static int mxt_get_object_table(struct mxt_data *data) { + struct i2c_client *client = data->client; + size_t table_size; int error; int i; - u16 reg; - u8 reportid = 0; - u8 buf[MXT_OBJECT_SIZE]; + u8 reportid; + + table_size = data->info.object_num * sizeof(struct mxt_object); + error = __mxt_read_reg(client, MXT_OBJECT_START, table_size, + data->object_table); + if (error) + return error; + /* Valid Report IDs start counting from 1 */ + reportid = 1; for (i = 0; i < data->info.object_num; i++) { struct mxt_object *object = data->object_table + i; + u8 min_id, max_id; - reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i; - error = mxt_read_object_table(data->client, reg, buf); - if (error) - return error; - - object->type = buf[0]; - object->start_address = (buf[2] << 8) | buf[1]; - object->size = buf[3]; - object->instances = buf[4]; - object->num_report_ids = buf[5]; + le16_to_cpus(&object->start_address); if (object->num_report_ids) { + min_id = reportid; reportid += object->num_report_ids * (object->instances + 1); - object->max_reportid = reportid; + max_id = reportid - 1; + } else { + min_id = 0; + max_id = 0; + } + + dev_dbg(&data->client->dev, + "Type %2d Start %3d Size %3d Instances %2d ReportIDs %3u : %3u\n", + object->type, object->start_address, object->size + 1, + object->instances + 1, min_id, max_id); + + switch (object->type) { + case MXT_TOUCH_MULTI_T9: + data->T9_reportid_min = min_id; + data->T9_reportid_max = max_id; + break; } } @@ -754,6 +758,8 @@ static void mxt_free_object_table(struct mxt_data *data) { kfree(data->object_table); data->object_table = NULL; + data->T9_reportid_min = 0; + data->T9_reportid_max = 0; } static int mxt_initialize(struct mxt_data *data) -- cgit v1.2.2 From 04a79181c40d3ad99885e7f799c799c153e93431 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:21 +0800 Subject: Input: atmel_mxt_ts - refactor reportid checking in mxt_interrupt This small refactor is in preparation for checking more report types in the mxt_interrupt message processing loop. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 48f3637aecaa..a9e0b541c638 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -554,6 +554,12 @@ static void mxt_input_touchevent(struct mxt_data *data, input_sync(input_dev); } +static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg) +{ + u8 id = msg->reportid; + return (id >= data->T9_reportid_min && id <= data->T9_reportid_max); +} + static irqreturn_t mxt_interrupt(int irq, void *dev_id) { struct mxt_data *data = dev_id; @@ -561,8 +567,6 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) struct device *dev = &data->client->dev; int id; u8 reportid; - u8 max_reportid; - u8 min_reportid; do { if (mxt_read_message(data, &message)) { @@ -572,11 +576,9 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) reportid = message.reportid; - max_reportid = data->T9_reportid_max; - min_reportid = data->T9_reportid_min; - id = reportid - min_reportid; + id = reportid - data->T9_reportid_min; - if (reportid >= min_reportid && reportid <= max_reportid) + if (mxt_is_T9_message(data, &message)) mxt_input_touchevent(data, &message, id); else mxt_dump_message(dev, &message); -- cgit v1.2.2 From cb15911509164f052f103e85a935f513f82e6b54 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:22 +0800 Subject: Input: atmel_mxt_ts - use T9 reportid range to init number of mt slots Atmel mxt devices can report one finger for each T9 reportid. Therefore, this range can be used to report the max number of MT-B slots to userspace instead of assuming a fixed 10. Note that mxt_initialized() must complete early, since the input_dev properties now depend on values in the object table. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index a9e0b541c638..2746b0dc7f36 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -212,8 +212,6 @@ /* Touchscreen absolute values */ #define MXT_MAX_AREA 0xff -#define MXT_MAX_FINGER 10 - struct mxt_info { u8 family_id; u8 variant_id; @@ -1086,6 +1084,7 @@ static int __devinit mxt_probe(struct i2c_client *client, struct mxt_data *data; struct input_dev *input_dev; int error; + unsigned int num_mt_slots; if (!pdata) return -EINVAL; @@ -1115,6 +1114,10 @@ static int __devinit mxt_probe(struct i2c_client *client, mxt_calc_resolution(data); + error = mxt_initialize(data); + if (error) + goto err_free_mem; + __set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit); __set_bit(BTN_TOUCH, input_dev->keybit); @@ -1128,9 +1131,10 @@ static int __devinit mxt_probe(struct i2c_client *client, 0, 255, 0, 0); /* For multi touch */ - error = input_mt_init_slots(input_dev, MXT_MAX_FINGER); + num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1; + error = input_mt_init_slots(input_dev, num_mt_slots); if (error) - goto err_free_mem; + goto err_free_object; input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, @@ -1143,10 +1147,6 @@ static int __devinit mxt_probe(struct i2c_client *client, input_set_drvdata(input_dev, data); i2c_set_clientdata(client, data); - error = mxt_initialize(data); - if (error) - goto err_free_mem; - error = request_threaded_irq(client->irq, NULL, mxt_interrupt, pdata->irqflags, client->name, data); if (error) { -- cgit v1.2.2 From 64464ae8e1d64fc9f63d9686d5e40b56ffa77203 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:23 +0800 Subject: Input: atmel_mxt_ts - send all MT-B slots in one input report Each interrupt contains information for all contacts with changing properties. Process all of this information at once, and send it all in a a single input report (ie input events ending in EV_SYN/SYN_REPORT). This patch was tested using an MXT224E. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 2746b0dc7f36..4c9a06c7eae3 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -547,9 +547,6 @@ static void mxt_input_touchevent(struct mxt_data *data, input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); } - - input_mt_report_pointer_emulation(input_dev, false); - input_sync(input_dev); } static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg) @@ -565,6 +562,7 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) struct device *dev = &data->client->dev; int id; u8 reportid; + bool update_input = false; do { if (mxt_read_message(data, &message)) { @@ -576,12 +574,19 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) id = reportid - data->T9_reportid_min; - if (mxt_is_T9_message(data, &message)) + if (mxt_is_T9_message(data, &message)) { mxt_input_touchevent(data, &message, id); - else + update_input = true; + } else { mxt_dump_message(dev, &message); + } } while (reportid != 0xff); + if (update_input) { + input_mt_report_pointer_emulation(data->input_dev, false); + input_sync(data->input_dev); + } + end: return IRQ_HANDLED; } -- cgit v1.2.2 From fdf804210f297b7a114fa7a216c2ab65b0f693da Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 28 Jun 2012 21:08:24 +0800 Subject: Input: atmel_mxt_ts - parse T6 reports The normal messages sent after boot or NVRAM update are T6 reports, containing a status, and the config memory checksum. Parse them and dump a useful info message. This patch tested on an MXT224E. Signed-off-by: Daniel Kurtz Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4c9a06c7eae3..37190ab1f817 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -248,6 +248,7 @@ struct mxt_data { unsigned int max_y; /* Cached parameters from object table */ + u8 T6_reportid; u8 T9_reportid_min; u8 T9_reportid_max; }; @@ -549,6 +550,11 @@ static void mxt_input_touchevent(struct mxt_data *data, } } +static unsigned mxt_extract_T6_csum(const u8 *csum) +{ + return csum[0] | (csum[1] << 8) | (csum[2] << 16); +} + static bool mxt_is_T9_message(struct mxt_data *data, struct mxt_message *msg) { u8 id = msg->reportid; @@ -559,8 +565,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) { struct mxt_data *data = dev_id; struct mxt_message message; + const u8 *payload = &message.message[0]; struct device *dev = &data->client->dev; - int id; u8 reportid; bool update_input = false; @@ -572,9 +578,13 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) reportid = message.reportid; - id = reportid - data->T9_reportid_min; - - if (mxt_is_T9_message(data, &message)) { + if (reportid == data->T6_reportid) { + u8 status = payload[0]; + unsigned csum = mxt_extract_T6_csum(&payload[1]); + dev_dbg(dev, "Status: %02x Config Checksum: %06x\n", + status, csum); + } else if (mxt_is_T9_message(data, &message)) { + int id = reportid - data->T9_reportid_min; mxt_input_touchevent(data, &message, id); update_input = true; } else { @@ -749,6 +759,9 @@ static int mxt_get_object_table(struct mxt_data *data) object->instances + 1, min_id, max_id); switch (object->type) { + case MXT_GEN_COMMAND_T6: + data->T6_reportid = min_id; + break; case MXT_TOUCH_MULTI_T9: data->T9_reportid_min = min_id; data->T9_reportid_max = max_id; @@ -763,8 +776,10 @@ static void mxt_free_object_table(struct mxt_data *data) { kfree(data->object_table); data->object_table = NULL; + data->T6_reportid = 0; data->T9_reportid_min = 0; data->T9_reportid_max = 0; + } static int mxt_initialize(struct mxt_data *data) -- cgit v1.2.2 From c45361a1287a74d327d72d4d2b96f4ac170653d9 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 5 Jul 2012 20:55:24 +0200 Subject: Revert "Input: atmel_mxt_ts - warn if sysfs could not be created" Dmitry: I understand that I am a bit late to the party :) but I do not agree with this change. Failure to create attributes is not sometihng that user could cause (at least not easily) and thus would not be a setup issue but something more severe. I believe we should fail loading the driver so sysfs attribute breakage will be noticed as soon as possible, instead of discovering it much much later in the process. This reverts commit 639900380062ecd78ee8b265ea23929c565469b4. Requested-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/touchscreen/atmel_mxt_ts.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 37190ab1f817..3ad942ca8725 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1184,10 +1184,13 @@ static int __devinit mxt_probe(struct i2c_client *client, error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) - dev_warn(&client->dev, "error creating sysfs entries.\n"); + goto err_unregister_device; return 0; +err_unregister_device: + input_unregister_device(input_dev); + input_dev = NULL; err_free_irq: free_irq(client->irq, data); err_free_object: -- cgit v1.2.2