linux/drivers/input/touchscreen/zet6223.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2016, Jelle van der Waa <jelle@vdwaa.nl>
   4 */
   5
   6#include <linux/delay.h>
   7#include <linux/i2c.h>
   8#include <linux/input.h>
   9#include <linux/input/mt.h>
  10#include <linux/input/touchscreen.h>
  11#include <linux/interrupt.h>
  12#include <linux/module.h>
  13#include <linux/regulator/consumer.h>
  14#include <asm/unaligned.h>
  15
  16#define ZET6223_MAX_FINGERS             16
  17#define ZET6223_MAX_PKT_SIZE            (3 + 4 * ZET6223_MAX_FINGERS)
  18
  19#define ZET6223_CMD_INFO                0xB2
  20#define ZET6223_CMD_INFO_LENGTH         17
  21#define ZET6223_VALID_PACKET            0x3c
  22
  23#define ZET6223_POWER_ON_DELAY_MSEC     30
  24
  25struct zet6223_ts {
  26        struct i2c_client *client;
  27        struct input_dev *input;
  28        struct regulator *vcc;
  29        struct regulator *vio;
  30        struct touchscreen_properties prop;
  31        struct regulator_bulk_data supplies[2];
  32        u16 max_x;
  33        u16 max_y;
  34        u8 fingernum;
  35};
  36
  37static int zet6223_start(struct input_dev *dev)
  38{
  39        struct zet6223_ts *ts = input_get_drvdata(dev);
  40
  41        enable_irq(ts->client->irq);
  42
  43        return 0;
  44}
  45
  46static void zet6223_stop(struct input_dev *dev)
  47{
  48        struct zet6223_ts *ts = input_get_drvdata(dev);
  49
  50        disable_irq(ts->client->irq);
  51}
  52
  53static irqreturn_t zet6223_irq(int irq, void *dev_id)
  54{
  55        struct zet6223_ts *ts = dev_id;
  56        u16 finger_bits;
  57
  58        /*
  59         * First 3 bytes are an identifier, two bytes of finger data.
  60         * X, Y data per finger is 4 bytes.
  61         */
  62        u8 bufsize = 3 + 4 * ts->fingernum;
  63        u8 buf[ZET6223_MAX_PKT_SIZE];
  64        int i;
  65        int ret;
  66        int error;
  67
  68        ret = i2c_master_recv(ts->client, buf, bufsize);
  69        if (ret != bufsize) {
  70                error = ret < 0 ? ret : -EIO;
  71                dev_err_ratelimited(&ts->client->dev,
  72                                    "Error reading input data: %d\n", error);
  73                return IRQ_HANDLED;
  74        }
  75
  76        if (buf[0] != ZET6223_VALID_PACKET)
  77                return IRQ_HANDLED;
  78
  79        finger_bits = get_unaligned_be16(buf + 1);
  80        for (i = 0; i < ts->fingernum; i++) {
  81                if (!(finger_bits & BIT(15 - i)))
  82                        continue;
  83
  84                input_mt_slot(ts->input, i);
  85                input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
  86                input_event(ts->input, EV_ABS, ABS_MT_POSITION_X,
  87                                ((buf[i + 3] >> 4) << 8) + buf[i + 4]);
  88                input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y,
  89                                ((buf[i + 3] & 0xF) << 8) + buf[i + 5]);
  90        }
  91
  92        input_mt_sync_frame(ts->input);
  93        input_sync(ts->input);
  94
  95        return IRQ_HANDLED;
  96}
  97
  98static void zet6223_power_off(void *_ts)
  99{
 100        struct zet6223_ts *ts = _ts;
 101
 102        regulator_bulk_disable(ARRAY_SIZE(ts->supplies), ts->supplies);
 103}
 104
 105static int zet6223_power_on(struct zet6223_ts *ts)
 106{
 107        struct device *dev = &ts->client->dev;
 108        int error;
 109
 110        ts->supplies[0].supply = "vio";
 111        ts->supplies[1].supply = "vcc";
 112
 113        error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->supplies),
 114                                        ts->supplies);
 115        if (error)
 116                return error;
 117
 118        error = regulator_bulk_enable(ARRAY_SIZE(ts->supplies), ts->supplies);
 119        if (error)
 120                return error;
 121
 122        msleep(ZET6223_POWER_ON_DELAY_MSEC);
 123
 124        error = devm_add_action_or_reset(dev, zet6223_power_off, ts);
 125        if (error) {
 126                dev_err(dev, "failed to install poweroff action: %d\n", error);
 127                return error;
 128        }
 129
 130        return 0;
 131}
 132
 133static int zet6223_query_device(struct zet6223_ts *ts)
 134{
 135        u8 buf[ZET6223_CMD_INFO_LENGTH];
 136        u8 cmd = ZET6223_CMD_INFO;
 137        int ret;
 138        int error;
 139
 140        ret = i2c_master_send(ts->client, &cmd, sizeof(cmd));
 141        if (ret != sizeof(cmd)) {
 142                error = ret < 0 ? ret : -EIO;
 143                dev_err(&ts->client->dev,
 144                        "touchpanel info cmd failed: %d\n", error);
 145                return error;
 146        }
 147
 148        ret = i2c_master_recv(ts->client, buf, sizeof(buf));
 149        if (ret != sizeof(buf)) {
 150                error = ret < 0 ? ret : -EIO;
 151                dev_err(&ts->client->dev,
 152                        "failed to retrieve touchpanel info: %d\n", error);
 153                return error;
 154        }
 155
 156        ts->fingernum = buf[15] & 0x7F;
 157        if (ts->fingernum > ZET6223_MAX_FINGERS) {
 158                dev_warn(&ts->client->dev,
 159                         "touchpanel reports %d fingers, limiting to %d\n",
 160                         ts->fingernum, ZET6223_MAX_FINGERS);
 161                ts->fingernum = ZET6223_MAX_FINGERS;
 162        }
 163
 164        ts->max_x = get_unaligned_le16(&buf[8]);
 165        ts->max_y = get_unaligned_le16(&buf[10]);
 166
 167        return 0;
 168}
 169
 170static int zet6223_probe(struct i2c_client *client,
 171                         const struct i2c_device_id *id)
 172{
 173        struct device *dev = &client->dev;
 174        struct zet6223_ts *ts;
 175        struct input_dev *input;
 176        int error;
 177
 178        if (!client->irq) {
 179                dev_err(dev, "no irq specified\n");
 180                return -EINVAL;
 181        }
 182
 183        ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
 184        if (!ts)
 185                return -ENOMEM;
 186
 187        ts->client = client;
 188
 189        error = zet6223_power_on(ts);
 190        if (error)
 191                return error;
 192
 193        error = zet6223_query_device(ts);
 194        if (error)
 195                return error;
 196
 197        ts->input = input = devm_input_allocate_device(dev);
 198        if (!input)
 199                return -ENOMEM;
 200
 201        input_set_drvdata(input, ts);
 202
 203        input->name = client->name;
 204        input->id.bustype = BUS_I2C;
 205        input->open = zet6223_start;
 206        input->close = zet6223_stop;
 207
 208        input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0);
 209        input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0);
 210
 211        touchscreen_parse_properties(input, true, &ts->prop);
 212
 213        error = input_mt_init_slots(input, ts->fingernum,
 214                                    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 215        if (error)
 216                return error;
 217
 218        error = devm_request_threaded_irq(dev, client->irq, NULL, zet6223_irq,
 219                                          IRQF_ONESHOT, client->name, ts);
 220        if (error) {
 221                dev_err(dev, "failed to request irq %d: %d\n",
 222                        client->irq, error);
 223                return error;
 224        }
 225
 226        zet6223_stop(input);
 227
 228        error = input_register_device(input);
 229        if (error)
 230                return error;
 231
 232        return 0;
 233}
 234
 235static const struct of_device_id zet6223_of_match[] = {
 236        { .compatible = "zeitec,zet6223" },
 237        { }
 238};
 239MODULE_DEVICE_TABLE(of, zet6223_of_match);
 240
 241static const struct i2c_device_id zet6223_id[] = {
 242        { "zet6223", 0},
 243        { }
 244};
 245MODULE_DEVICE_TABLE(i2c, zet6223_id);
 246
 247static struct i2c_driver zet6223_driver = {
 248        .driver = {
 249                .name = "zet6223",
 250                .of_match_table = zet6223_of_match,
 251        },
 252        .probe = zet6223_probe,
 253        .id_table = zet6223_id
 254};
 255module_i2c_driver(zet6223_driver);
 256
 257MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>");
 258MODULE_DESCRIPTION("ZEITEC zet622x I2C touchscreen driver");
 259MODULE_LICENSE("GPL");
 260