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