zet6223.c (5876B)
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");