linux/drivers/input/touchscreen/sis_i2c.c
<<
>>
Prefs
   1/*
   2 * Touch Screen driver for SiS 9200 family I2C Touch panels
   3 *
   4 * Copyright (C) 2015 SiS, Inc.
   5 * Copyright (C) 2016 Nextfour Group
   6 *
   7 * This software is licensed under the terms of the GNU General Public
   8 * License version 2, as published by the Free Software Foundation, and
   9 * may be copied, distributed, and modified under those terms.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/crc-itu-t.h>
  18#include <linux/delay.h>
  19#include <linux/i2c.h>
  20#include <linux/input.h>
  21#include <linux/input/mt.h>
  22#include <linux/interrupt.h>
  23#include <linux/gpio/consumer.h>
  24#include <linux/module.h>
  25#include <linux/slab.h>
  26#include <asm/unaligned.h>
  27
  28#define SIS_I2C_NAME            "sis_i2c_ts"
  29
  30/*
  31 * The I2C packet format:
  32 * le16         byte count
  33 * u8           Report ID
  34 * <contact data - variable length>
  35 * u8           Number of contacts
  36 * le16         Scan Time (optional)
  37 * le16         CRC
  38 *
  39 * One touch point information consists of 6+ bytes, the order is:
  40 * u8           contact state
  41 * u8           finger id
  42 * le16         x axis
  43 * le16         y axis
  44 * u8           contact width (optional)
  45 * u8           contact height (optional)
  46 * u8           pressure (optional)
  47 *
  48 * Maximum amount of data transmitted in one shot is 64 bytes, if controller
  49 * needs to report more contacts than fit in one packet it will send true
  50 * number of contacts in first packet and 0 as number of contacts in second
  51 * packet.
  52 */
  53
  54#define SIS_MAX_PACKET_SIZE             64
  55
  56#define SIS_PKT_LEN_OFFSET              0
  57#define SIS_PKT_REPORT_OFFSET           2 /* Report ID/type */
  58#define SIS_PKT_CONTACT_OFFSET          3 /* First contact */
  59
  60#define SIS_SCAN_TIME_LEN               2
  61
  62/* Supported report types */
  63#define SIS_ALL_IN_ONE_PACKAGE          0x10
  64#define SIS_PKT_IS_TOUCH(x)             (((x) & 0x0f) == 0x01)
  65#define SIS_PKT_IS_HIDI2C(x)            (((x) & 0x0f) == 0x06)
  66
  67/* Contact properties within report */
  68#define SIS_PKT_HAS_AREA(x)             ((x) & BIT(4))
  69#define SIS_PKT_HAS_PRESSURE(x)         ((x) & BIT(5))
  70#define SIS_PKT_HAS_SCANTIME(x)         ((x) & BIT(6))
  71
  72/* Contact size */
  73#define SIS_BASE_LEN_PER_CONTACT        6
  74#define SIS_AREA_LEN_PER_CONTACT        2
  75#define SIS_PRESSURE_LEN_PER_CONTACT    1
  76
  77/* Offsets within contact data */
  78#define SIS_CONTACT_STATUS_OFFSET       0
  79#define SIS_CONTACT_ID_OFFSET           1 /* Contact ID */
  80#define SIS_CONTACT_X_OFFSET            2
  81#define SIS_CONTACT_Y_OFFSET            4
  82#define SIS_CONTACT_WIDTH_OFFSET        6
  83#define SIS_CONTACT_HEIGHT_OFFSET       7
  84#define SIS_CONTACT_PRESSURE_OFFSET(id) (SIS_PKT_HAS_AREA(id) ? 8 : 6)
  85
  86/* Individual contact state */
  87#define SIS_STATUS_UP                   0x0
  88#define SIS_STATUS_DOWN                 0x3
  89
  90/* Touchscreen parameters */
  91#define SIS_MAX_FINGERS                 10
  92#define SIS_MAX_X                       4095
  93#define SIS_MAX_Y                       4095
  94#define SIS_MAX_PRESSURE                255
  95
  96/* Resolution diagonal */
  97#define SIS_AREA_LENGTH_LONGER          5792
  98/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
  99#define SIS_AREA_LENGTH_SHORT           5792
 100#define SIS_AREA_UNIT                   (5792 / 32)
 101
 102struct sis_ts_data {
 103        struct i2c_client *client;
 104        struct input_dev *input;
 105
 106        struct gpio_desc *attn_gpio;
 107        struct gpio_desc *reset_gpio;
 108
 109        u8 packet[SIS_MAX_PACKET_SIZE];
 110};
 111
 112static int sis_read_packet(struct i2c_client *client, u8 *buf,
 113                           unsigned int *num_contacts,
 114                           unsigned int *contact_size)
 115{
 116        int count_idx;
 117        int ret;
 118        u16 len;
 119        u16 crc, pkg_crc;
 120        u8 report_id;
 121
 122        ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE);
 123        if (ret <= 0)
 124                return -EIO;
 125
 126        len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]);
 127        if (len > SIS_MAX_PACKET_SIZE) {
 128                dev_err(&client->dev,
 129                        "%s: invalid packet length (%d vs %d)\n",
 130                        __func__, len, SIS_MAX_PACKET_SIZE);
 131                return -E2BIG;
 132        }
 133
 134        if (len < 10)
 135                return -EINVAL;
 136
 137        report_id = buf[SIS_PKT_REPORT_OFFSET];
 138        count_idx  = len - 1;
 139        *contact_size = SIS_BASE_LEN_PER_CONTACT;
 140
 141        if (report_id != SIS_ALL_IN_ONE_PACKAGE) {
 142                if (SIS_PKT_IS_TOUCH(report_id)) {
 143                        /*
 144                         * Calculate CRC ignoring packet length
 145                         * in the beginning and CRC transmitted
 146                         * at the end of the packet.
 147                         */
 148                        crc = crc_itu_t(0, buf + 2, len - 2 - 2);
 149                        pkg_crc = get_unaligned_le16(&buf[len - 2]);
 150
 151                        if (crc != pkg_crc) {
 152                                dev_err(&client->dev,
 153                                        "%s: CRC Error (%d vs %d)\n",
 154                                        __func__, crc, pkg_crc);
 155                                return -EINVAL;
 156                        }
 157
 158                        count_idx -= 2;
 159
 160                } else if (!SIS_PKT_IS_HIDI2C(report_id)) {
 161                        dev_err(&client->dev,
 162                                "%s: invalid packet ID %#02x\n",
 163                                __func__, report_id);
 164                        return -EINVAL;
 165                }
 166
 167                if (SIS_PKT_HAS_SCANTIME(report_id))
 168                        count_idx -= SIS_SCAN_TIME_LEN;
 169
 170                if (SIS_PKT_HAS_AREA(report_id))
 171                        *contact_size += SIS_AREA_LEN_PER_CONTACT;
 172                if (SIS_PKT_HAS_PRESSURE(report_id))
 173                        *contact_size += SIS_PRESSURE_LEN_PER_CONTACT;
 174        }
 175
 176        *num_contacts = buf[count_idx];
 177        return 0;
 178}
 179
 180static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id)
 181{
 182        struct input_dev *input = ts->input;
 183        int slot;
 184        u8 status = data[SIS_CONTACT_STATUS_OFFSET];
 185        u8 pressure;
 186        u8 height, width;
 187        u16 x, y;
 188
 189        if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) {
 190                dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n",
 191                        data[SIS_CONTACT_STATUS_OFFSET]);
 192                return -EINVAL;
 193        }
 194
 195        slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]);
 196        if (slot < 0)
 197                return -ENOENT;
 198
 199        input_mt_slot(input, slot);
 200        input_mt_report_slot_state(input, MT_TOOL_FINGER,
 201                                   status == SIS_STATUS_DOWN);
 202
 203        if (status == SIS_STATUS_DOWN) {
 204                pressure = height = width = 1;
 205                if (id != SIS_ALL_IN_ONE_PACKAGE) {
 206                        if (SIS_PKT_HAS_AREA(id)) {
 207                                width = data[SIS_CONTACT_WIDTH_OFFSET];
 208                                height = data[SIS_CONTACT_HEIGHT_OFFSET];
 209                        }
 210
 211                        if (SIS_PKT_HAS_PRESSURE(id))
 212                                pressure =
 213                                        data[SIS_CONTACT_PRESSURE_OFFSET(id)];
 214                }
 215
 216                x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]);
 217                y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]);
 218
 219                input_report_abs(input, ABS_MT_TOUCH_MAJOR,
 220                                 width * SIS_AREA_UNIT);
 221                input_report_abs(input, ABS_MT_TOUCH_MINOR,
 222                                 height * SIS_AREA_UNIT);
 223                input_report_abs(input, ABS_MT_PRESSURE, pressure);
 224                input_report_abs(input, ABS_MT_POSITION_X, x);
 225                input_report_abs(input, ABS_MT_POSITION_Y, y);
 226        }
 227
 228        return 0;
 229}
 230
 231static void sis_ts_handle_packet(struct sis_ts_data *ts)
 232{
 233        const u8 *contact;
 234        unsigned int num_to_report = 0;
 235        unsigned int num_contacts;
 236        unsigned int num_reported;
 237        unsigned int contact_size;
 238        int error;
 239        u8 report_id;
 240
 241        do {
 242                error = sis_read_packet(ts->client, ts->packet,
 243                                        &num_contacts, &contact_size);
 244                if (error)
 245                        break;
 246
 247                if (num_to_report == 0) {
 248                        num_to_report = num_contacts;
 249                } else if (num_contacts != 0) {
 250                        dev_err(&ts->client->dev,
 251                                "%s: nonzero (%d) point count in tail packet\n",
 252                                __func__, num_contacts);
 253                        break;
 254                }
 255
 256                report_id = ts->packet[SIS_PKT_REPORT_OFFSET];
 257                contact = &ts->packet[SIS_PKT_CONTACT_OFFSET];
 258                num_reported = 0;
 259
 260                while (num_to_report > 0) {
 261                        error = sis_ts_report_contact(ts, contact, report_id);
 262                        if (error)
 263                                break;
 264
 265                        contact += contact_size;
 266                        num_to_report--;
 267                        num_reported++;
 268
 269                        if (report_id != SIS_ALL_IN_ONE_PACKAGE &&
 270                            num_reported >= 5) {
 271                                /*
 272                                 * The remainder of contacts is sent
 273                                 * in the 2nd packet.
 274                                 */
 275                                break;
 276                        }
 277                }
 278        } while (num_to_report > 0);
 279
 280        input_mt_sync_frame(ts->input);
 281        input_sync(ts->input);
 282}
 283
 284static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
 285{
 286        struct sis_ts_data *ts = dev_id;
 287
 288        do {
 289                sis_ts_handle_packet(ts);
 290        } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio));
 291
 292        return IRQ_HANDLED;
 293}
 294
 295static void sis_ts_reset(struct sis_ts_data *ts)
 296{
 297        if (ts->reset_gpio) {
 298                /* Get out of reset */
 299                usleep_range(1000, 2000);
 300                gpiod_set_value(ts->reset_gpio, 1);
 301                usleep_range(1000, 2000);
 302                gpiod_set_value(ts->reset_gpio, 0);
 303                msleep(100);
 304        }
 305}
 306
 307static int sis_ts_probe(struct i2c_client *client,
 308                        const struct i2c_device_id *id)
 309{
 310        struct sis_ts_data *ts;
 311        struct input_dev *input;
 312        int error;
 313
 314        ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
 315        if (!ts)
 316                return -ENOMEM;
 317
 318        ts->client = client;
 319
 320        ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
 321                                                "attn", GPIOD_IN);
 322        if (IS_ERR(ts->attn_gpio)) {
 323                error = PTR_ERR(ts->attn_gpio);
 324                if (error != -EPROBE_DEFER)
 325                        dev_err(&client->dev,
 326                                "Failed to get attention GPIO: %d\n", error);
 327                return error;
 328        }
 329
 330        ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
 331                                                 "reset", GPIOD_OUT_LOW);
 332        if (IS_ERR(ts->reset_gpio)) {
 333                error = PTR_ERR(ts->reset_gpio);
 334                if (error != -EPROBE_DEFER)
 335                        dev_err(&client->dev,
 336                                "Failed to get reset GPIO: %d\n", error);
 337                return error;
 338        }
 339
 340        sis_ts_reset(ts);
 341
 342        ts->input = input = devm_input_allocate_device(&client->dev);
 343        if (!input) {
 344                dev_err(&client->dev, "Failed to allocate input device\n");
 345                return -ENOMEM;
 346        }
 347
 348        input->name = "SiS Touchscreen";
 349        input->id.bustype = BUS_I2C;
 350
 351        input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
 352        input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
 353        input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0);
 354        input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
 355                             0, SIS_AREA_LENGTH_LONGER, 0, 0);
 356        input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
 357                             0, SIS_AREA_LENGTH_SHORT, 0, 0);
 358
 359        error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT);
 360        if (error) {
 361                dev_err(&client->dev,
 362                        "Failed to initialize MT slots: %d\n", error);
 363                return error;
 364        }
 365
 366        error = devm_request_threaded_irq(&client->dev, client->irq,
 367                                          NULL, sis_ts_irq_handler,
 368                                          IRQF_ONESHOT,
 369                                          client->name, ts);
 370        if (error) {
 371                dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
 372                return error;
 373        }
 374
 375        error = input_register_device(ts->input);
 376        if (error) {
 377                dev_err(&client->dev,
 378                        "Failed to register input device: %d\n", error);
 379                return error;
 380        }
 381
 382        return 0;
 383}
 384
 385#ifdef CONFIG_OF
 386static const struct of_device_id sis_ts_dt_ids[] = {
 387        { .compatible = "sis,9200-ts" },
 388        { /* sentinel */ }
 389};
 390MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
 391#endif
 392
 393static const struct i2c_device_id sis_ts_id[] = {
 394        { SIS_I2C_NAME, 0 },
 395        { "9200-ts",    0 },
 396        { /* sentinel */  }
 397};
 398MODULE_DEVICE_TABLE(i2c, sis_ts_id);
 399
 400static struct i2c_driver sis_ts_driver = {
 401        .driver = {
 402                .name   = SIS_I2C_NAME,
 403                .of_match_table = of_match_ptr(sis_ts_dt_ids),
 404        },
 405        .probe          = sis_ts_probe,
 406        .id_table       = sis_ts_id,
 407};
 408module_i2c_driver(sis_ts_driver);
 409
 410MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
 411MODULE_LICENSE("GPL v2");
 412MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>");
 413