1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27e577a17SAhmet Inan /* 37e577a17SAhmet Inan * Driver for I2C connected EETI EXC3000 multiple touch controller 47e577a17SAhmet Inan * 57e577a17SAhmet Inan * Copyright (C) 2017 Ahmet Inan <inan@distec.de> 67e577a17SAhmet Inan * 77e577a17SAhmet Inan * minimal implementation based on egalax_ts.c and egalax_i2c.c 87e577a17SAhmet Inan */ 97e577a17SAhmet Inan 10*bac6eb72SAndreas Helbech Kleist #include <linux/acpi.h> 117e577a17SAhmet Inan #include <linux/bitops.h> 1227aced19SSebastian Reichel #include <linux/delay.h> 137e577a17SAhmet Inan #include <linux/device.h> 1427aced19SSebastian Reichel #include <linux/gpio/consumer.h> 157e577a17SAhmet Inan #include <linux/i2c.h> 167e577a17SAhmet Inan #include <linux/input.h> 177e577a17SAhmet Inan #include <linux/input/mt.h> 187e577a17SAhmet Inan #include <linux/input/touchscreen.h> 197e577a17SAhmet Inan #include <linux/interrupt.h> 207e577a17SAhmet Inan #include <linux/module.h> 217e577a17SAhmet Inan #include <linux/of.h> 223bdd21c6SSebastian Reichel #include <linux/sizes.h> 237e577a17SAhmet Inan #include <linux/timer.h> 247e577a17SAhmet Inan #include <asm/unaligned.h> 257e577a17SAhmet Inan 267e577a17SAhmet Inan #define EXC3000_NUM_SLOTS 10 277e577a17SAhmet Inan #define EXC3000_SLOTS_PER_FRAME 5 287e577a17SAhmet Inan #define EXC3000_LEN_FRAME 66 29102feb1dSLucas Stach #define EXC3000_LEN_VENDOR_REQUEST 68 307e577a17SAhmet Inan #define EXC3000_LEN_POINT 10 313bdd21c6SSebastian Reichel 32d862a306SSebastian Reichel #define EXC3000_LEN_MODEL_NAME 16 33d862a306SSebastian Reichel #define EXC3000_LEN_FW_VERSION 16 34d862a306SSebastian Reichel 35a63d0120SLucas Stach #define EXC3000_VENDOR_EVENT 0x03 363bdd21c6SSebastian Reichel #define EXC3000_MT1_EVENT 0x06 373bdd21c6SSebastian Reichel #define EXC3000_MT2_EVENT 0x18 383bdd21c6SSebastian Reichel 397e577a17SAhmet Inan #define EXC3000_TIMEOUT_MS 100 407e577a17SAhmet Inan 4127aced19SSebastian Reichel #define EXC3000_RESET_MS 10 4227aced19SSebastian Reichel #define EXC3000_READY_MS 100 4327aced19SSebastian Reichel 443bdd21c6SSebastian Reichel static const struct i2c_device_id exc3000_id[]; 453bdd21c6SSebastian Reichel 463bdd21c6SSebastian Reichel struct eeti_dev_info { 473bdd21c6SSebastian Reichel const char *name; 483bdd21c6SSebastian Reichel int max_xy; 493bdd21c6SSebastian Reichel }; 503bdd21c6SSebastian Reichel 513bdd21c6SSebastian Reichel enum eeti_dev_id { 523bdd21c6SSebastian Reichel EETI_EXC3000, 533bdd21c6SSebastian Reichel EETI_EXC80H60, 543bdd21c6SSebastian Reichel EETI_EXC80H84, 553bdd21c6SSebastian Reichel }; 563bdd21c6SSebastian Reichel 573bdd21c6SSebastian Reichel static struct eeti_dev_info exc3000_info[] = { 583bdd21c6SSebastian Reichel [EETI_EXC3000] = { 593bdd21c6SSebastian Reichel .name = "EETI EXC3000 Touch Screen", 603bdd21c6SSebastian Reichel .max_xy = SZ_4K - 1, 613bdd21c6SSebastian Reichel }, 623bdd21c6SSebastian Reichel [EETI_EXC80H60] = { 633bdd21c6SSebastian Reichel .name = "EETI EXC80H60 Touch Screen", 643bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 653bdd21c6SSebastian Reichel }, 663bdd21c6SSebastian Reichel [EETI_EXC80H84] = { 673bdd21c6SSebastian Reichel .name = "EETI EXC80H84 Touch Screen", 683bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 693bdd21c6SSebastian Reichel }, 703bdd21c6SSebastian Reichel }; 713bdd21c6SSebastian Reichel 727e577a17SAhmet Inan struct exc3000_data { 737e577a17SAhmet Inan struct i2c_client *client; 743bdd21c6SSebastian Reichel const struct eeti_dev_info *info; 757e577a17SAhmet Inan struct input_dev *input; 767e577a17SAhmet Inan struct touchscreen_properties prop; 7727aced19SSebastian Reichel struct gpio_desc *reset; 787e577a17SAhmet Inan struct timer_list timer; 797e577a17SAhmet Inan u8 buf[2 * EXC3000_LEN_FRAME]; 80d862a306SSebastian Reichel struct completion wait_event; 81d862a306SSebastian Reichel struct mutex query_lock; 827e577a17SAhmet Inan }; 837e577a17SAhmet Inan 847e577a17SAhmet Inan static void exc3000_report_slots(struct input_dev *input, 857e577a17SAhmet Inan struct touchscreen_properties *prop, 867e577a17SAhmet Inan const u8 *buf, int num) 877e577a17SAhmet Inan { 887e577a17SAhmet Inan for (; num--; buf += EXC3000_LEN_POINT) { 897e577a17SAhmet Inan if (buf[0] & BIT(0)) { 907e577a17SAhmet Inan input_mt_slot(input, buf[1]); 917e577a17SAhmet Inan input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 927e577a17SAhmet Inan touchscreen_report_pos(input, prop, 937e577a17SAhmet Inan get_unaligned_le16(buf + 2), 947e577a17SAhmet Inan get_unaligned_le16(buf + 4), 957e577a17SAhmet Inan true); 967e577a17SAhmet Inan } 977e577a17SAhmet Inan } 987e577a17SAhmet Inan } 997e577a17SAhmet Inan 1007e577a17SAhmet Inan static void exc3000_timer(struct timer_list *t) 1017e577a17SAhmet Inan { 1027e577a17SAhmet Inan struct exc3000_data *data = from_timer(data, t, timer); 1037e577a17SAhmet Inan 1047e577a17SAhmet Inan input_mt_sync_frame(data->input); 1057e577a17SAhmet Inan input_sync(data->input); 1067e577a17SAhmet Inan } 1077e577a17SAhmet Inan 108a63d0120SLucas Stach static inline void exc3000_schedule_timer(struct exc3000_data *data) 109a63d0120SLucas Stach { 110a63d0120SLucas Stach mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); 111a63d0120SLucas Stach } 112a63d0120SLucas Stach 11379c81d13SDmitry Torokhov static void exc3000_shutdown_timer(void *timer) 11479c81d13SDmitry Torokhov { 11579c81d13SDmitry Torokhov timer_shutdown_sync(timer); 11679c81d13SDmitry Torokhov } 11779c81d13SDmitry Torokhov 1183bdd21c6SSebastian Reichel static int exc3000_read_frame(struct exc3000_data *data, u8 *buf) 1197e577a17SAhmet Inan { 1203bdd21c6SSebastian Reichel struct i2c_client *client = data->client; 1217e577a17SAhmet Inan int ret; 1227e577a17SAhmet Inan 1237e577a17SAhmet Inan ret = i2c_master_send(client, "'", 2); 1247e577a17SAhmet Inan if (ret < 0) 1257e577a17SAhmet Inan return ret; 1267e577a17SAhmet Inan 1277e577a17SAhmet Inan if (ret != 2) 1287e577a17SAhmet Inan return -EIO; 1297e577a17SAhmet Inan 1307e577a17SAhmet Inan ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME); 1317e577a17SAhmet Inan if (ret < 0) 1327e577a17SAhmet Inan return ret; 1337e577a17SAhmet Inan 1347e577a17SAhmet Inan if (ret != EXC3000_LEN_FRAME) 1357e577a17SAhmet Inan return -EIO; 1367e577a17SAhmet Inan 1373bdd21c6SSebastian Reichel if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME) 1383bdd21c6SSebastian Reichel return -EINVAL; 1393bdd21c6SSebastian Reichel 1407e577a17SAhmet Inan return 0; 1417e577a17SAhmet Inan } 1427e577a17SAhmet Inan 143a63d0120SLucas Stach static int exc3000_handle_mt_event(struct exc3000_data *data) 1447e577a17SAhmet Inan { 145a63d0120SLucas Stach struct input_dev *input = data->input; 146a63d0120SLucas Stach int ret, total_slots; 147a63d0120SLucas Stach u8 *buf = data->buf; 1487e577a17SAhmet Inan 149a63d0120SLucas Stach total_slots = buf[3]; 150a63d0120SLucas Stach if (!total_slots || total_slots > EXC3000_NUM_SLOTS) { 151a63d0120SLucas Stach ret = -EINVAL; 152a63d0120SLucas Stach goto out_fail; 153a63d0120SLucas Stach } 1547e577a17SAhmet Inan 155a63d0120SLucas Stach if (total_slots > EXC3000_SLOTS_PER_FRAME) { 1567e577a17SAhmet Inan /* Read 2nd frame to get the rest of the contacts. */ 157a63d0120SLucas Stach ret = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME); 158a63d0120SLucas Stach if (ret) 159a63d0120SLucas Stach goto out_fail; 1607e577a17SAhmet Inan 1617e577a17SAhmet Inan /* 2nd chunk must have number of contacts set to 0. */ 162a63d0120SLucas Stach if (buf[EXC3000_LEN_FRAME + 3] != 0) { 163a63d0120SLucas Stach ret = -EINVAL; 164a63d0120SLucas Stach goto out_fail; 165a63d0120SLucas Stach } 1667e577a17SAhmet Inan } 1677e577a17SAhmet Inan 168a63d0120SLucas Stach /* 169a63d0120SLucas Stach * We read full state successfully, no contacts will be "stuck". 170a63d0120SLucas Stach */ 171a63d0120SLucas Stach del_timer_sync(&data->timer); 172a63d0120SLucas Stach 173a63d0120SLucas Stach while (total_slots > 0) { 174a63d0120SLucas Stach int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); 175a63d0120SLucas Stach 176a63d0120SLucas Stach exc3000_report_slots(input, &data->prop, buf + 4, slots); 177a63d0120SLucas Stach total_slots -= slots; 178a63d0120SLucas Stach buf += EXC3000_LEN_FRAME; 179a63d0120SLucas Stach } 180a63d0120SLucas Stach 181a63d0120SLucas Stach input_mt_sync_frame(input); 182a63d0120SLucas Stach input_sync(input); 183a63d0120SLucas Stach 1847e577a17SAhmet Inan return 0; 185a63d0120SLucas Stach 186a63d0120SLucas Stach out_fail: 187a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 188a63d0120SLucas Stach exc3000_schedule_timer(data); 189a63d0120SLucas Stach 190a63d0120SLucas Stach return ret; 1917e577a17SAhmet Inan } 1927e577a17SAhmet Inan 1937e577a17SAhmet Inan static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 1947e577a17SAhmet Inan { 1957e577a17SAhmet Inan struct exc3000_data *data = dev_id; 1967e577a17SAhmet Inan u8 *buf = data->buf; 197a63d0120SLucas Stach int ret; 1987e577a17SAhmet Inan 199a63d0120SLucas Stach ret = exc3000_read_frame(data, buf); 200a63d0120SLucas Stach if (ret) { 201a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 202a63d0120SLucas Stach exc3000_schedule_timer(data); 203a63d0120SLucas Stach goto out; 204a63d0120SLucas Stach } 205a63d0120SLucas Stach 206a63d0120SLucas Stach switch (buf[2]) { 207a63d0120SLucas Stach case EXC3000_VENDOR_EVENT: 208d862a306SSebastian Reichel complete(&data->wait_event); 209a63d0120SLucas Stach break; 210a63d0120SLucas Stach 211a63d0120SLucas Stach case EXC3000_MT1_EVENT: 212a63d0120SLucas Stach case EXC3000_MT2_EVENT: 213a63d0120SLucas Stach exc3000_handle_mt_event(data); 214a63d0120SLucas Stach break; 215a63d0120SLucas Stach 216a63d0120SLucas Stach default: 217a63d0120SLucas Stach break; 218d862a306SSebastian Reichel } 219d862a306SSebastian Reichel 2207e577a17SAhmet Inan out: 2217e577a17SAhmet Inan return IRQ_HANDLED; 2227e577a17SAhmet Inan } 2237e577a17SAhmet Inan 224102feb1dSLucas Stach static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, 225102feb1dSLucas Stach u8 request_len, u8 *response, int timeout) 226102feb1dSLucas Stach { 227102feb1dSLucas Stach u8 buf[EXC3000_LEN_VENDOR_REQUEST] = { 0x67, 0x00, 0x42, 0x00, 0x03 }; 228102feb1dSLucas Stach int ret; 2296bb7144cSMiaoqian Lin unsigned long time_left; 230102feb1dSLucas Stach 231102feb1dSLucas Stach mutex_lock(&data->query_lock); 232102feb1dSLucas Stach 233102feb1dSLucas Stach reinit_completion(&data->wait_event); 234102feb1dSLucas Stach 235102feb1dSLucas Stach buf[5] = request_len; 236102feb1dSLucas Stach memcpy(&buf[6], request, request_len); 237102feb1dSLucas Stach 238102feb1dSLucas Stach ret = i2c_master_send(data->client, buf, EXC3000_LEN_VENDOR_REQUEST); 239102feb1dSLucas Stach if (ret < 0) 240102feb1dSLucas Stach goto out_unlock; 241102feb1dSLucas Stach 242102feb1dSLucas Stach if (response) { 2436bb7144cSMiaoqian Lin time_left = wait_for_completion_timeout(&data->wait_event, 244102feb1dSLucas Stach timeout * HZ); 2456bb7144cSMiaoqian Lin if (time_left == 0) { 246102feb1dSLucas Stach ret = -ETIMEDOUT; 247102feb1dSLucas Stach goto out_unlock; 248102feb1dSLucas Stach } 249102feb1dSLucas Stach 250102feb1dSLucas Stach if (data->buf[3] >= EXC3000_LEN_FRAME) { 251102feb1dSLucas Stach ret = -ENOSPC; 252102feb1dSLucas Stach goto out_unlock; 253102feb1dSLucas Stach } 254102feb1dSLucas Stach 255102feb1dSLucas Stach memcpy(response, &data->buf[4], data->buf[3]); 256102feb1dSLucas Stach ret = data->buf[3]; 257102feb1dSLucas Stach } 258102feb1dSLucas Stach 259102feb1dSLucas Stach out_unlock: 260102feb1dSLucas Stach mutex_unlock(&data->query_lock); 261102feb1dSLucas Stach 262102feb1dSLucas Stach return ret; 263102feb1dSLucas Stach } 264102feb1dSLucas Stach 265d862a306SSebastian Reichel static ssize_t fw_version_show(struct device *dev, 266d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 267d862a306SSebastian Reichel { 268d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 269d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 270102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 271102feb1dSLucas Stach int ret; 272d862a306SSebastian Reichel 273c929ac9eSLucas Stach /* query bootloader info */ 274c929ac9eSLucas Stach ret = exc3000_vendor_data_request(data, 275c929ac9eSLucas Stach (u8[]){0x39, 0x02}, 2, response, 1); 276c929ac9eSLucas Stach if (ret < 0) 277c929ac9eSLucas Stach return ret; 278c929ac9eSLucas Stach 279c929ac9eSLucas Stach /* 280c929ac9eSLucas Stach * If the bootloader version is non-zero then the device is in 281c929ac9eSLucas Stach * bootloader mode and won't answer a query for the application FW 282c929ac9eSLucas Stach * version, so we just use the bootloader version info. 283c929ac9eSLucas Stach */ 284c929ac9eSLucas Stach if (response[2] || response[3]) 285c929ac9eSLucas Stach return sprintf(buf, "%d.%d\n", response[2], response[3]); 286c929ac9eSLucas Stach 287102feb1dSLucas Stach ret = exc3000_vendor_data_request(data, (u8[]){'D'}, 1, response, 1); 288102feb1dSLucas Stach if (ret < 0) 289102feb1dSLucas Stach return ret; 290d862a306SSebastian Reichel 291102feb1dSLucas Stach return sprintf(buf, "%s\n", &response[1]); 292d862a306SSebastian Reichel } 293d862a306SSebastian Reichel static DEVICE_ATTR_RO(fw_version); 294d862a306SSebastian Reichel 295d862a306SSebastian Reichel static ssize_t model_show(struct device *dev, 296d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 297d862a306SSebastian Reichel { 298d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 299d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 300102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 301102feb1dSLucas Stach int ret; 302d862a306SSebastian Reichel 303102feb1dSLucas Stach ret = exc3000_vendor_data_request(data, (u8[]){'E'}, 1, response, 1); 304102feb1dSLucas Stach if (ret < 0) 305102feb1dSLucas Stach return ret; 306d862a306SSebastian Reichel 307102feb1dSLucas Stach return sprintf(buf, "%s\n", &response[1]); 308d862a306SSebastian Reichel } 309d862a306SSebastian Reichel static DEVICE_ATTR_RO(model); 310d862a306SSebastian Reichel 311ad117c55SLucas Stach static ssize_t type_show(struct device *dev, 312ad117c55SLucas Stach struct device_attribute *attr, char *buf) 313ad117c55SLucas Stach { 314ad117c55SLucas Stach struct i2c_client *client = to_i2c_client(dev); 315ad117c55SLucas Stach struct exc3000_data *data = i2c_get_clientdata(client); 316ad117c55SLucas Stach u8 response[EXC3000_LEN_FRAME]; 317ad117c55SLucas Stach int ret; 318ad117c55SLucas Stach 319ad117c55SLucas Stach ret = exc3000_vendor_data_request(data, (u8[]){'F'}, 1, response, 1); 320ad117c55SLucas Stach if (ret < 0) 321ad117c55SLucas Stach return ret; 322ad117c55SLucas Stach 323ad117c55SLucas Stach return sprintf(buf, "%s\n", &response[1]); 324ad117c55SLucas Stach } 325ad117c55SLucas Stach static DEVICE_ATTR_RO(type); 326ad117c55SLucas Stach 327d862a306SSebastian Reichel static struct attribute *sysfs_attrs[] = { 328d862a306SSebastian Reichel &dev_attr_fw_version.attr, 329d862a306SSebastian Reichel &dev_attr_model.attr, 330ad117c55SLucas Stach &dev_attr_type.attr, 331d862a306SSebastian Reichel NULL 332d862a306SSebastian Reichel }; 333d862a306SSebastian Reichel 334d862a306SSebastian Reichel static struct attribute_group exc3000_attribute_group = { 335d862a306SSebastian Reichel .attrs = sysfs_attrs 336d862a306SSebastian Reichel }; 337d862a306SSebastian Reichel 338deae5764SSebastian Reichel static int exc3000_probe(struct i2c_client *client) 3397e577a17SAhmet Inan { 3407e577a17SAhmet Inan struct exc3000_data *data; 3417e577a17SAhmet Inan struct input_dev *input; 342d862a306SSebastian Reichel int error, max_xy, retry; 3437e577a17SAhmet Inan 3447e577a17SAhmet Inan data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 3457e577a17SAhmet Inan if (!data) 3467e577a17SAhmet Inan return -ENOMEM; 3477e577a17SAhmet Inan 3487e577a17SAhmet Inan data->client = client; 3493bdd21c6SSebastian Reichel data->info = device_get_match_data(&client->dev); 3503bdd21c6SSebastian Reichel if (!data->info) { 3513bdd21c6SSebastian Reichel enum eeti_dev_id eeti_dev_id = 3523bdd21c6SSebastian Reichel i2c_match_id(exc3000_id, client)->driver_data; 3533bdd21c6SSebastian Reichel data->info = &exc3000_info[eeti_dev_id]; 3543bdd21c6SSebastian Reichel } 3557e577a17SAhmet Inan timer_setup(&data->timer, exc3000_timer, 0); 356d862a306SSebastian Reichel init_completion(&data->wait_event); 357d862a306SSebastian Reichel mutex_init(&data->query_lock); 3587e577a17SAhmet Inan 35927aced19SSebastian Reichel data->reset = devm_gpiod_get_optional(&client->dev, "reset", 36027aced19SSebastian Reichel GPIOD_OUT_HIGH); 36127aced19SSebastian Reichel if (IS_ERR(data->reset)) 36227aced19SSebastian Reichel return PTR_ERR(data->reset); 36327aced19SSebastian Reichel 36427aced19SSebastian Reichel if (data->reset) { 36527aced19SSebastian Reichel msleep(EXC3000_RESET_MS); 36627aced19SSebastian Reichel gpiod_set_value_cansleep(data->reset, 0); 36727aced19SSebastian Reichel msleep(EXC3000_READY_MS); 36827aced19SSebastian Reichel } 36927aced19SSebastian Reichel 3707e577a17SAhmet Inan input = devm_input_allocate_device(&client->dev); 3717e577a17SAhmet Inan if (!input) 3727e577a17SAhmet Inan return -ENOMEM; 3737e577a17SAhmet Inan 3747e577a17SAhmet Inan data->input = input; 375d862a306SSebastian Reichel input_set_drvdata(input, data); 3767e577a17SAhmet Inan 3773bdd21c6SSebastian Reichel input->name = data->info->name; 3787e577a17SAhmet Inan input->id.bustype = BUS_I2C; 3797e577a17SAhmet Inan 3803bdd21c6SSebastian Reichel max_xy = data->info->max_xy; 3813bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 3823bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 3833bdd21c6SSebastian Reichel 3847e577a17SAhmet Inan touchscreen_parse_properties(input, true, &data->prop); 3857e577a17SAhmet Inan 3867e577a17SAhmet Inan error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, 3877e577a17SAhmet Inan INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 3887e577a17SAhmet Inan if (error) 3897e577a17SAhmet Inan return error; 3907e577a17SAhmet Inan 3917e577a17SAhmet Inan error = input_register_device(input); 3927e577a17SAhmet Inan if (error) 3937e577a17SAhmet Inan return error; 3947e577a17SAhmet Inan 39579c81d13SDmitry Torokhov error = devm_add_action_or_reset(&client->dev, exc3000_shutdown_timer, 39679c81d13SDmitry Torokhov &data->timer); 39779c81d13SDmitry Torokhov if (error) 39879c81d13SDmitry Torokhov return error; 39979c81d13SDmitry Torokhov 4007e577a17SAhmet Inan error = devm_request_threaded_irq(&client->dev, client->irq, 4017e577a17SAhmet Inan NULL, exc3000_interrupt, IRQF_ONESHOT, 4027e577a17SAhmet Inan client->name, data); 4037e577a17SAhmet Inan if (error) 4047e577a17SAhmet Inan return error; 4057e577a17SAhmet Inan 406d862a306SSebastian Reichel /* 407d862a306SSebastian Reichel * I²C does not have built-in recovery, so retry on failure. This 408d862a306SSebastian Reichel * ensures, that the device probe will not fail for temporary issues 409d862a306SSebastian Reichel * on the bus. This is not needed for the sysfs calls (userspace 410d862a306SSebastian Reichel * will receive the error code and can start another query) and 411d862a306SSebastian Reichel * cannot be done for touch events (but that only means loosing one 412d862a306SSebastian Reichel * or two touch events anyways). 413d862a306SSebastian Reichel */ 414d862a306SSebastian Reichel for (retry = 0; retry < 3; retry++) { 415102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 416102feb1dSLucas Stach 417102feb1dSLucas Stach error = exc3000_vendor_data_request(data, (u8[]){'E'}, 1, 418102feb1dSLucas Stach response, 1); 419102feb1dSLucas Stach if (error > 0) { 420102feb1dSLucas Stach dev_dbg(&client->dev, "TS Model: %s", &response[1]); 421102feb1dSLucas Stach error = 0; 422d862a306SSebastian Reichel break; 423102feb1dSLucas Stach } 424d862a306SSebastian Reichel dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n", 425d862a306SSebastian Reichel retry + 1, error); 426d862a306SSebastian Reichel } 427d862a306SSebastian Reichel 428d862a306SSebastian Reichel if (error) 429d862a306SSebastian Reichel return error; 430d862a306SSebastian Reichel 431d862a306SSebastian Reichel i2c_set_clientdata(client, data); 432d862a306SSebastian Reichel 433d862a306SSebastian Reichel error = devm_device_add_group(&client->dev, &exc3000_attribute_group); 434d862a306SSebastian Reichel if (error) 435d862a306SSebastian Reichel return error; 436d862a306SSebastian Reichel 4377e577a17SAhmet Inan return 0; 4387e577a17SAhmet Inan } 4397e577a17SAhmet Inan 4407e577a17SAhmet Inan static const struct i2c_device_id exc3000_id[] = { 4413bdd21c6SSebastian Reichel { "exc3000", EETI_EXC3000 }, 4423bdd21c6SSebastian Reichel { "exc80h60", EETI_EXC80H60 }, 4433bdd21c6SSebastian Reichel { "exc80h84", EETI_EXC80H84 }, 4447e577a17SAhmet Inan { } 4457e577a17SAhmet Inan }; 4467e577a17SAhmet Inan MODULE_DEVICE_TABLE(i2c, exc3000_id); 4477e577a17SAhmet Inan 4487e577a17SAhmet Inan #ifdef CONFIG_OF 4497e577a17SAhmet Inan static const struct of_device_id exc3000_of_match[] = { 4503bdd21c6SSebastian Reichel { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] }, 4513bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] }, 4523bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] }, 4537e577a17SAhmet Inan { } 4547e577a17SAhmet Inan }; 4557e577a17SAhmet Inan MODULE_DEVICE_TABLE(of, exc3000_of_match); 4567e577a17SAhmet Inan #endif 4577e577a17SAhmet Inan 458*bac6eb72SAndreas Helbech Kleist #ifdef CONFIG_ACPI 459*bac6eb72SAndreas Helbech Kleist static const struct acpi_device_id exc3000_acpi_match[] = { 460*bac6eb72SAndreas Helbech Kleist { "EGA00001", .driver_data = (kernel_ulong_t)&exc3000_info[EETI_EXC80H60] }, 461*bac6eb72SAndreas Helbech Kleist { } 462*bac6eb72SAndreas Helbech Kleist }; 463*bac6eb72SAndreas Helbech Kleist MODULE_DEVICE_TABLE(acpi, exc3000_acpi_match); 464*bac6eb72SAndreas Helbech Kleist #endif 465*bac6eb72SAndreas Helbech Kleist 4667e577a17SAhmet Inan static struct i2c_driver exc3000_driver = { 4677e577a17SAhmet Inan .driver = { 4687e577a17SAhmet Inan .name = "exc3000", 4697e577a17SAhmet Inan .of_match_table = of_match_ptr(exc3000_of_match), 470*bac6eb72SAndreas Helbech Kleist .acpi_match_table = ACPI_PTR(exc3000_acpi_match), 4717e577a17SAhmet Inan }, 4727e577a17SAhmet Inan .id_table = exc3000_id, 473d8bde56dSUwe Kleine-König .probe = exc3000_probe, 4747e577a17SAhmet Inan }; 4757e577a17SAhmet Inan 4767e577a17SAhmet Inan module_i2c_driver(exc3000_driver); 4777e577a17SAhmet Inan 4787e577a17SAhmet Inan MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); 4797e577a17SAhmet Inan MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); 4807e577a17SAhmet Inan MODULE_LICENSE("GPL v2"); 481