lkml.org 
[lkml]   [2013]   [Jun]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 34/51] Input: atmel_mxt_ts - Implement T44 message handling
    Date
    maXTouch chips allow the reading of multiple messages in a single I2C
    transaction. The number of messages available to be read is given by the value
    in the T44 object which is located directly before the T5 object.

    Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
    Acked-by: Benson Leung <bleung@chromium.org>
    ---
    drivers/input/touchscreen/atmel_mxt_ts.c | 190 +++++++++++++++++++++++++-----
    1 file changed, 158 insertions(+), 32 deletions(-)

    diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
    index ef68bf1..5d51133 100644
    --- a/drivers/input/touchscreen/atmel_mxt_ts.c
    +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
    @@ -246,6 +246,7 @@ struct mxt_data {
    unsigned int max_y;
    bool in_bootloader;
    u16 mem_size;
    + u8 max_reportid;
    u32 config_crc;
    u32 info_crc;
    u8 bootloader_addr;
    @@ -253,6 +254,8 @@ struct mxt_data {
    u8 *msg_buf;
    u8 t6_status;
    bool update_input;
    + u8 last_message_count;
    + u8 num_touchids;

    /* Cached parameters from object table */
    u16 T5_address;
    @@ -263,6 +266,7 @@ struct mxt_data {
    u8 T9_reportid_min;
    u8 T9_reportid_max;
    u8 T19_reportid;
    + u16 T44_address;

    /* for fw update in bootloader */
    struct completion bl_completion;
    @@ -786,30 +790,143 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
    return 1;
    }

    -static int mxt_read_and_process_message(struct mxt_data *data)
    +static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
    {
    struct device *dev = &data->client->dev;
    int ret;
    + int i;
    + u8 num_valid = 0;
    +
    + /* Safety check for msg_buf */
    + if (count > data->max_reportid)
    + return -EINVAL;

    + /* Process remaining messages if necessary */
    ret = __mxt_read_reg(data->client, data->T5_address,
    - data->T5_msg_size, data->msg_buf);
    + data->T5_msg_size * count, data->msg_buf);
    if (ret) {
    - dev_err(dev, "Error %d reading message\n", ret);
    + dev_err(dev, "Failed to read %u messages (%d)\n", count, ret);
    return ret;
    }

    - return mxt_proc_message(data, data->msg_buf);
    + for (i = 0; i < count; i++) {
    + ret = mxt_proc_message(data,
    + data->msg_buf + data->T5_msg_size * i);
    +
    + if (ret == 1)
    + num_valid++;
    + }
    +
    + /* return number of messages read */
    + return num_valid;
    }

    -static irqreturn_t mxt_process_messages_until_invalid(struct mxt_data *data)
    +static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
    {
    + struct device *dev = &data->client->dev;
    int ret;
    + u8 count, num_left;

    - do {
    - ret = mxt_read_and_process_message(data);
    + /* Read T44 and T5 together */
    + ret = __mxt_read_reg(data->client, data->T44_address,
    + data->T5_msg_size + 1, data->msg_buf);
    + if (ret) {
    + dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret);
    + return IRQ_NONE;
    + }
    +
    + count = data->msg_buf[0];
    +
    + if (count == 0) {
    + dev_warn(dev, "Interrupt triggered but zero messages\n");
    + return IRQ_NONE;
    + } else if (count > data->max_reportid) {
    + dev_err(dev, "T44 count %d exceeded max report id\n", count);
    + count = data->max_reportid;
    + }
    +
    + /* Process first message */
    + ret = mxt_proc_message(data, data->msg_buf + 1);
    + if (ret < 0) {
    + dev_warn(dev, "Unexpected invalid message\n");
    + return IRQ_NONE;
    + }
    +
    + num_left = count - 1;
    +
    + /* Process remaining messages if necessary */
    + if (num_left) {
    + ret = mxt_read_and_process_messages(data, num_left);
    if (ret < 0)
    + goto end;
    + else if (ret != num_left)
    + dev_warn(dev, "Unexpected invalid message\n");
    + }
    +
    +end:
    + if (data->update_input) {
    + mxt_input_sync(data->input_dev);
    + data->update_input = false;
    + }
    +
    + return IRQ_HANDLED;
    +}
    +
    +static int mxt_process_messages_until_invalid(struct mxt_data *data)
    +{
    + struct device *dev = &data->client->dev;
    + int count, read;
    + u8 tries = 2;
    +
    + count = data->max_reportid;
    +
    + /* Read messages until we force an invalid */
    + do {
    + read = mxt_read_and_process_messages(data, count);
    + if (read < count)
    + return 0;
    + } while (--tries);
    +
    + if (data->update_input) {
    + mxt_input_sync(data->input_dev);
    + data->update_input = false;
    + }
    +
    + dev_err(dev, "CHG pin isn't cleared\n");
    + return -EBUSY;
    +}
    +
    +static irqreturn_t mxt_process_messages(struct mxt_data *data)
    +{
    + int total_handled, num_handled;
    + u8 count = data->last_message_count;
    +
    + if (count < 1 || count > data->max_reportid)
    + count = 1;
    +
    + /* include final invalid message */
    + total_handled = mxt_read_and_process_messages(data, count + 1);
    + if (total_handled < 0)
    + return IRQ_NONE;
    + /* if there were invalid messages, then we are done */
    + else if (total_handled <= count)
    + goto update_count;
    +
    + /* read two at a time until an invalid message or else we reach
    + * reportid limit */
    + do {
    + num_handled = mxt_read_and_process_messages(data, 2);
    + if (num_handled < 0)
    return IRQ_NONE;
    - } while (ret > 0);
    +
    + total_handled += num_handled;
    +
    + if (num_handled < 2)
    + break;
    + } while (total_handled < data->num_touchids);
    +
    +update_count:
    + data->last_message_count = total_handled;

    if (data->enable_reporting && data->update_input) {
    mxt_input_sync(data->input_dev);
    @@ -832,7 +949,11 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
    if (!data->object_table)
    return IRQ_NONE;

    - return mxt_process_messages_until_invalid(data);
    + if (data->T44_address) {
    + return mxt_process_messages_t44(data);
    + } else {
    + return mxt_process_messages(data);
    + }
    }

    static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
    @@ -1257,32 +1378,13 @@ recheck:
    }
    }

    -static int mxt_make_highchg(struct mxt_data *data)
    -{
    - struct device *dev = &data->client->dev;
    - int count = 10;
    - int ret;
    -
    - /* Read messages until we force an invalid */
    - do {
    - ret = mxt_read_and_process_message(data);
    - if (ret == 0)
    - return 0;
    - else if (ret < 0)
    - return ret;
    - } while (--count);
    -
    - dev_err(dev, "CHG pin isn't cleared\n");
    - return -EBUSY;
    -}
    -
    static int mxt_acquire_irq(struct mxt_data *data)
    {
    int error;

    enable_irq(data->irq);

    - error = mxt_make_highchg(data);
    + error = mxt_process_messages_until_invalid(data);
    if (error)
    return error;

    @@ -1317,6 +1419,8 @@ static void mxt_free_object_table(struct mxt_data *data)
    data->T9_reportid_min = 0;
    data->T9_reportid_max = 0;
    data->T19_reportid = 0;
    + data->T44_address = 0;
    + data->max_reportid = 0;
    }

    static int mxt_get_object_table(struct mxt_data *data)
    @@ -1361,8 +1465,14 @@ static int mxt_get_object_table(struct mxt_data *data)

    switch (object->type) {
    case MXT_GEN_MESSAGE_T5:
    - /* CRC not enabled, therefore don't read last byte */
    - data->T5_msg_size = mxt_obj_size(object) - 1;
    + if (data->info.family_id == 0x80) {
    + /* On mXT224 read and discard unused CRC byte
    + * otherwise DMA reads are misaligned */
    + data->T5_msg_size = mxt_obj_size(object);
    + } else {
    + /* CRC not enabled, so skip last byte */
    + data->T5_msg_size = mxt_obj_size(object) - 1;
    + }
    data->T5_address = object->start_address;
    case MXT_GEN_COMMAND_T6:
    data->T6_reportid = min_id;
    @@ -1374,6 +1484,11 @@ static int mxt_get_object_table(struct mxt_data *data)
    case MXT_TOUCH_MULTI_T9:
    data->T9_reportid_min = min_id;
    data->T9_reportid_max = max_id;
    + data->num_touchids = object->num_report_ids
    + * mxt_obj_instances(object);
    + break;
    + case MXT_SPT_MESSAGECOUNT_T44:
    + data->T44_address = object->start_address;
    break;
    case MXT_SPT_GPIOPWM_T19:
    data->T19_reportid = min_id;
    @@ -1387,7 +1502,18 @@ static int mxt_get_object_table(struct mxt_data *data)
    data->mem_size = end_address + 1;
    }

    - data->msg_buf = kzalloc(data->T5_msg_size, GFP_KERNEL);
    + /* Store maximum reportid */
    + data->max_reportid = reportid;
    +
    + /* If T44 exists, T5 position has to be directly after */
    + if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
    + dev_err(&client->dev, "Invalid T44 position\n");
    + error = -EINVAL;
    + goto free_object_table;
    + }
    +
    + data->msg_buf = kcalloc(data->max_reportid,
    + data->T5_msg_size, GFP_KERNEL);
    if (!data->msg_buf) {
    dev_err(&client->dev, "Failed to allocate message buffer\n");
    error = -ENOMEM;
    --
    1.7.10.4


    \
     
     \ /
      Last update: 2013-06-27 16:41    [W:4.071 / U:0.836 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site