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 107e577a17SAhmet Inan #include <linux/bitops.h> 1127aced19SSebastian Reichel #include <linux/delay.h> 127e577a17SAhmet Inan #include <linux/device.h> 1327aced19SSebastian Reichel #include <linux/gpio/consumer.h> 147e577a17SAhmet Inan #include <linux/i2c.h> 157e577a17SAhmet Inan #include <linux/input.h> 167e577a17SAhmet Inan #include <linux/input/mt.h> 177e577a17SAhmet Inan #include <linux/input/touchscreen.h> 187e577a17SAhmet Inan #include <linux/interrupt.h> 197e577a17SAhmet Inan #include <linux/module.h> 207e577a17SAhmet Inan #include <linux/of.h> 213bdd21c6SSebastian Reichel #include <linux/sizes.h> 227e577a17SAhmet Inan #include <linux/timer.h> 237e577a17SAhmet Inan #include <asm/unaligned.h> 247e577a17SAhmet Inan 257e577a17SAhmet Inan #define EXC3000_NUM_SLOTS 10 267e577a17SAhmet Inan #define EXC3000_SLOTS_PER_FRAME 5 277e577a17SAhmet Inan #define EXC3000_LEN_FRAME 66 287e577a17SAhmet Inan #define EXC3000_LEN_POINT 10 293bdd21c6SSebastian Reichel 30*d862a306SSebastian Reichel #define EXC3000_LEN_MODEL_NAME 16 31*d862a306SSebastian Reichel #define EXC3000_LEN_FW_VERSION 16 32*d862a306SSebastian Reichel 333bdd21c6SSebastian Reichel #define EXC3000_MT1_EVENT 0x06 343bdd21c6SSebastian Reichel #define EXC3000_MT2_EVENT 0x18 353bdd21c6SSebastian Reichel 367e577a17SAhmet Inan #define EXC3000_TIMEOUT_MS 100 377e577a17SAhmet Inan 3827aced19SSebastian Reichel #define EXC3000_RESET_MS 10 3927aced19SSebastian Reichel #define EXC3000_READY_MS 100 4027aced19SSebastian Reichel 413bdd21c6SSebastian Reichel static const struct i2c_device_id exc3000_id[]; 423bdd21c6SSebastian Reichel 433bdd21c6SSebastian Reichel struct eeti_dev_info { 443bdd21c6SSebastian Reichel const char *name; 453bdd21c6SSebastian Reichel int max_xy; 463bdd21c6SSebastian Reichel }; 473bdd21c6SSebastian Reichel 483bdd21c6SSebastian Reichel enum eeti_dev_id { 493bdd21c6SSebastian Reichel EETI_EXC3000, 503bdd21c6SSebastian Reichel EETI_EXC80H60, 513bdd21c6SSebastian Reichel EETI_EXC80H84, 523bdd21c6SSebastian Reichel }; 533bdd21c6SSebastian Reichel 543bdd21c6SSebastian Reichel static struct eeti_dev_info exc3000_info[] = { 553bdd21c6SSebastian Reichel [EETI_EXC3000] = { 563bdd21c6SSebastian Reichel .name = "EETI EXC3000 Touch Screen", 573bdd21c6SSebastian Reichel .max_xy = SZ_4K - 1, 583bdd21c6SSebastian Reichel }, 593bdd21c6SSebastian Reichel [EETI_EXC80H60] = { 603bdd21c6SSebastian Reichel .name = "EETI EXC80H60 Touch Screen", 613bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 623bdd21c6SSebastian Reichel }, 633bdd21c6SSebastian Reichel [EETI_EXC80H84] = { 643bdd21c6SSebastian Reichel .name = "EETI EXC80H84 Touch Screen", 653bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 663bdd21c6SSebastian Reichel }, 673bdd21c6SSebastian Reichel }; 683bdd21c6SSebastian Reichel 697e577a17SAhmet Inan struct exc3000_data { 707e577a17SAhmet Inan struct i2c_client *client; 713bdd21c6SSebastian Reichel const struct eeti_dev_info *info; 727e577a17SAhmet Inan struct input_dev *input; 737e577a17SAhmet Inan struct touchscreen_properties prop; 7427aced19SSebastian Reichel struct gpio_desc *reset; 757e577a17SAhmet Inan struct timer_list timer; 767e577a17SAhmet Inan u8 buf[2 * EXC3000_LEN_FRAME]; 77*d862a306SSebastian Reichel struct completion wait_event; 78*d862a306SSebastian Reichel struct mutex query_lock; 79*d862a306SSebastian Reichel int query_result; 80*d862a306SSebastian Reichel char model[EXC3000_LEN_MODEL_NAME]; 81*d862a306SSebastian Reichel char fw_version[EXC3000_LEN_FW_VERSION]; 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 1083bdd21c6SSebastian Reichel static int exc3000_read_frame(struct exc3000_data *data, u8 *buf) 1097e577a17SAhmet Inan { 1103bdd21c6SSebastian Reichel struct i2c_client *client = data->client; 1113bdd21c6SSebastian Reichel u8 expected_event = EXC3000_MT1_EVENT; 1127e577a17SAhmet Inan int ret; 1137e577a17SAhmet Inan 1143bdd21c6SSebastian Reichel if (data->info->max_xy == SZ_16K - 1) 1153bdd21c6SSebastian Reichel expected_event = EXC3000_MT2_EVENT; 1163bdd21c6SSebastian Reichel 1177e577a17SAhmet Inan ret = i2c_master_send(client, "'", 2); 1187e577a17SAhmet Inan if (ret < 0) 1197e577a17SAhmet Inan return ret; 1207e577a17SAhmet Inan 1217e577a17SAhmet Inan if (ret != 2) 1227e577a17SAhmet Inan return -EIO; 1237e577a17SAhmet Inan 1247e577a17SAhmet Inan ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME); 1257e577a17SAhmet Inan if (ret < 0) 1267e577a17SAhmet Inan return ret; 1277e577a17SAhmet Inan 1287e577a17SAhmet Inan if (ret != EXC3000_LEN_FRAME) 1297e577a17SAhmet Inan return -EIO; 1307e577a17SAhmet Inan 1313bdd21c6SSebastian Reichel if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME) 1323bdd21c6SSebastian Reichel return -EINVAL; 1333bdd21c6SSebastian Reichel 1343bdd21c6SSebastian Reichel if (buf[2] != expected_event) 1357e577a17SAhmet Inan return -EINVAL; 1367e577a17SAhmet Inan 1377e577a17SAhmet Inan return 0; 1387e577a17SAhmet Inan } 1397e577a17SAhmet Inan 1403bdd21c6SSebastian Reichel static int exc3000_read_data(struct exc3000_data *data, 1417e577a17SAhmet Inan u8 *buf, int *n_slots) 1427e577a17SAhmet Inan { 1437e577a17SAhmet Inan int error; 1447e577a17SAhmet Inan 1453bdd21c6SSebastian Reichel error = exc3000_read_frame(data, buf); 1467e577a17SAhmet Inan if (error) 1477e577a17SAhmet Inan return error; 1487e577a17SAhmet Inan 1497e577a17SAhmet Inan *n_slots = buf[3]; 1507e577a17SAhmet Inan if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS) 1517e577a17SAhmet Inan return -EINVAL; 1527e577a17SAhmet Inan 1537e577a17SAhmet Inan if (*n_slots > EXC3000_SLOTS_PER_FRAME) { 1547e577a17SAhmet Inan /* Read 2nd frame to get the rest of the contacts. */ 1553bdd21c6SSebastian Reichel error = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME); 1567e577a17SAhmet Inan if (error) 1577e577a17SAhmet Inan return error; 1587e577a17SAhmet Inan 1597e577a17SAhmet Inan /* 2nd chunk must have number of contacts set to 0. */ 1607e577a17SAhmet Inan if (buf[EXC3000_LEN_FRAME + 3] != 0) 1617e577a17SAhmet Inan return -EINVAL; 1627e577a17SAhmet Inan } 1637e577a17SAhmet Inan 1647e577a17SAhmet Inan return 0; 1657e577a17SAhmet Inan } 1667e577a17SAhmet Inan 167*d862a306SSebastian Reichel static int exc3000_query_interrupt(struct exc3000_data *data) 168*d862a306SSebastian Reichel { 169*d862a306SSebastian Reichel u8 *buf = data->buf; 170*d862a306SSebastian Reichel int error; 171*d862a306SSebastian Reichel 172*d862a306SSebastian Reichel error = i2c_master_recv(data->client, buf, EXC3000_LEN_FRAME); 173*d862a306SSebastian Reichel if (error < 0) 174*d862a306SSebastian Reichel return error; 175*d862a306SSebastian Reichel 176*d862a306SSebastian Reichel if (buf[0] != 'B') 177*d862a306SSebastian Reichel return -EPROTO; 178*d862a306SSebastian Reichel 179*d862a306SSebastian Reichel if (buf[4] == 'E') 180*d862a306SSebastian Reichel strlcpy(data->model, buf + 5, sizeof(data->model)); 181*d862a306SSebastian Reichel else if (buf[4] == 'D') 182*d862a306SSebastian Reichel strlcpy(data->fw_version, buf + 5, sizeof(data->fw_version)); 183*d862a306SSebastian Reichel else 184*d862a306SSebastian Reichel return -EPROTO; 185*d862a306SSebastian Reichel 186*d862a306SSebastian Reichel return 0; 187*d862a306SSebastian Reichel } 188*d862a306SSebastian Reichel 1897e577a17SAhmet Inan static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 1907e577a17SAhmet Inan { 1917e577a17SAhmet Inan struct exc3000_data *data = dev_id; 1927e577a17SAhmet Inan struct input_dev *input = data->input; 1937e577a17SAhmet Inan u8 *buf = data->buf; 1947e577a17SAhmet Inan int slots, total_slots; 1957e577a17SAhmet Inan int error; 1967e577a17SAhmet Inan 197*d862a306SSebastian Reichel if (mutex_is_locked(&data->query_lock)) { 198*d862a306SSebastian Reichel data->query_result = exc3000_query_interrupt(data); 199*d862a306SSebastian Reichel complete(&data->wait_event); 200*d862a306SSebastian Reichel goto out; 201*d862a306SSebastian Reichel } 202*d862a306SSebastian Reichel 2033bdd21c6SSebastian Reichel error = exc3000_read_data(data, buf, &total_slots); 2047e577a17SAhmet Inan if (error) { 2057e577a17SAhmet Inan /* Schedule a timer to release "stuck" contacts */ 2067e577a17SAhmet Inan mod_timer(&data->timer, 2077e577a17SAhmet Inan jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); 2087e577a17SAhmet Inan goto out; 2097e577a17SAhmet Inan } 2107e577a17SAhmet Inan 2117e577a17SAhmet Inan /* 2127e577a17SAhmet Inan * We read full state successfully, no contacts will be "stuck". 2137e577a17SAhmet Inan */ 2147e577a17SAhmet Inan del_timer_sync(&data->timer); 2157e577a17SAhmet Inan 2167e577a17SAhmet Inan while (total_slots > 0) { 2177e577a17SAhmet Inan slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); 2187e577a17SAhmet Inan exc3000_report_slots(input, &data->prop, buf + 4, slots); 2197e577a17SAhmet Inan total_slots -= slots; 2207e577a17SAhmet Inan buf += EXC3000_LEN_FRAME; 2217e577a17SAhmet Inan } 2227e577a17SAhmet Inan 2237e577a17SAhmet Inan input_mt_sync_frame(input); 2247e577a17SAhmet Inan input_sync(input); 2257e577a17SAhmet Inan 2267e577a17SAhmet Inan out: 2277e577a17SAhmet Inan return IRQ_HANDLED; 2287e577a17SAhmet Inan } 2297e577a17SAhmet Inan 230*d862a306SSebastian Reichel static ssize_t fw_version_show(struct device *dev, 231*d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 232*d862a306SSebastian Reichel { 233*d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 234*d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 235*d862a306SSebastian Reichel static const u8 request[68] = { 236*d862a306SSebastian Reichel 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'D', 0x00 237*d862a306SSebastian Reichel }; 238*d862a306SSebastian Reichel int error; 239*d862a306SSebastian Reichel 240*d862a306SSebastian Reichel mutex_lock(&data->query_lock); 241*d862a306SSebastian Reichel 242*d862a306SSebastian Reichel data->query_result = -ETIMEDOUT; 243*d862a306SSebastian Reichel reinit_completion(&data->wait_event); 244*d862a306SSebastian Reichel 245*d862a306SSebastian Reichel error = i2c_master_send(client, request, sizeof(request)); 246*d862a306SSebastian Reichel if (error < 0) { 247*d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 248*d862a306SSebastian Reichel return error; 249*d862a306SSebastian Reichel } 250*d862a306SSebastian Reichel 251*d862a306SSebastian Reichel wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 252*d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 253*d862a306SSebastian Reichel 254*d862a306SSebastian Reichel if (data->query_result < 0) 255*d862a306SSebastian Reichel return data->query_result; 256*d862a306SSebastian Reichel 257*d862a306SSebastian Reichel return sprintf(buf, "%s\n", data->fw_version); 258*d862a306SSebastian Reichel } 259*d862a306SSebastian Reichel static DEVICE_ATTR_RO(fw_version); 260*d862a306SSebastian Reichel 261*d862a306SSebastian Reichel static ssize_t exc3000_get_model(struct exc3000_data *data) 262*d862a306SSebastian Reichel { 263*d862a306SSebastian Reichel static const u8 request[68] = { 264*d862a306SSebastian Reichel 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00 265*d862a306SSebastian Reichel }; 266*d862a306SSebastian Reichel struct i2c_client *client = data->client; 267*d862a306SSebastian Reichel int error; 268*d862a306SSebastian Reichel 269*d862a306SSebastian Reichel mutex_lock(&data->query_lock); 270*d862a306SSebastian Reichel data->query_result = -ETIMEDOUT; 271*d862a306SSebastian Reichel reinit_completion(&data->wait_event); 272*d862a306SSebastian Reichel 273*d862a306SSebastian Reichel error = i2c_master_send(client, request, sizeof(request)); 274*d862a306SSebastian Reichel if (error < 0) { 275*d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 276*d862a306SSebastian Reichel return error; 277*d862a306SSebastian Reichel } 278*d862a306SSebastian Reichel 279*d862a306SSebastian Reichel wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 280*d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 281*d862a306SSebastian Reichel 282*d862a306SSebastian Reichel return data->query_result; 283*d862a306SSebastian Reichel } 284*d862a306SSebastian Reichel 285*d862a306SSebastian Reichel static ssize_t model_show(struct device *dev, 286*d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 287*d862a306SSebastian Reichel { 288*d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 289*d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 290*d862a306SSebastian Reichel int error; 291*d862a306SSebastian Reichel 292*d862a306SSebastian Reichel error = exc3000_get_model(data); 293*d862a306SSebastian Reichel if (error < 0) 294*d862a306SSebastian Reichel return error; 295*d862a306SSebastian Reichel 296*d862a306SSebastian Reichel return sprintf(buf, "%s\n", data->model); 297*d862a306SSebastian Reichel } 298*d862a306SSebastian Reichel static DEVICE_ATTR_RO(model); 299*d862a306SSebastian Reichel 300*d862a306SSebastian Reichel static struct attribute *sysfs_attrs[] = { 301*d862a306SSebastian Reichel &dev_attr_fw_version.attr, 302*d862a306SSebastian Reichel &dev_attr_model.attr, 303*d862a306SSebastian Reichel NULL 304*d862a306SSebastian Reichel }; 305*d862a306SSebastian Reichel 306*d862a306SSebastian Reichel static struct attribute_group exc3000_attribute_group = { 307*d862a306SSebastian Reichel .attrs = sysfs_attrs 308*d862a306SSebastian Reichel }; 309*d862a306SSebastian Reichel 310deae5764SSebastian Reichel static int exc3000_probe(struct i2c_client *client) 3117e577a17SAhmet Inan { 3127e577a17SAhmet Inan struct exc3000_data *data; 3137e577a17SAhmet Inan struct input_dev *input; 314*d862a306SSebastian Reichel int error, max_xy, retry; 3157e577a17SAhmet Inan 3167e577a17SAhmet Inan data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 3177e577a17SAhmet Inan if (!data) 3187e577a17SAhmet Inan return -ENOMEM; 3197e577a17SAhmet Inan 3207e577a17SAhmet Inan data->client = client; 3213bdd21c6SSebastian Reichel data->info = device_get_match_data(&client->dev); 3223bdd21c6SSebastian Reichel if (!data->info) { 3233bdd21c6SSebastian Reichel enum eeti_dev_id eeti_dev_id = 3243bdd21c6SSebastian Reichel i2c_match_id(exc3000_id, client)->driver_data; 3253bdd21c6SSebastian Reichel data->info = &exc3000_info[eeti_dev_id]; 3263bdd21c6SSebastian Reichel } 3277e577a17SAhmet Inan timer_setup(&data->timer, exc3000_timer, 0); 328*d862a306SSebastian Reichel init_completion(&data->wait_event); 329*d862a306SSebastian Reichel mutex_init(&data->query_lock); 3307e577a17SAhmet Inan 33127aced19SSebastian Reichel data->reset = devm_gpiod_get_optional(&client->dev, "reset", 33227aced19SSebastian Reichel GPIOD_OUT_HIGH); 33327aced19SSebastian Reichel if (IS_ERR(data->reset)) 33427aced19SSebastian Reichel return PTR_ERR(data->reset); 33527aced19SSebastian Reichel 33627aced19SSebastian Reichel if (data->reset) { 33727aced19SSebastian Reichel msleep(EXC3000_RESET_MS); 33827aced19SSebastian Reichel gpiod_set_value_cansleep(data->reset, 0); 33927aced19SSebastian Reichel msleep(EXC3000_READY_MS); 34027aced19SSebastian Reichel } 34127aced19SSebastian Reichel 3427e577a17SAhmet Inan input = devm_input_allocate_device(&client->dev); 3437e577a17SAhmet Inan if (!input) 3447e577a17SAhmet Inan return -ENOMEM; 3457e577a17SAhmet Inan 3467e577a17SAhmet Inan data->input = input; 347*d862a306SSebastian Reichel input_set_drvdata(input, data); 3487e577a17SAhmet Inan 3493bdd21c6SSebastian Reichel input->name = data->info->name; 3507e577a17SAhmet Inan input->id.bustype = BUS_I2C; 3517e577a17SAhmet Inan 3523bdd21c6SSebastian Reichel max_xy = data->info->max_xy; 3533bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 3543bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 3553bdd21c6SSebastian Reichel 3567e577a17SAhmet Inan touchscreen_parse_properties(input, true, &data->prop); 3577e577a17SAhmet Inan 3587e577a17SAhmet Inan error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, 3597e577a17SAhmet Inan INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 3607e577a17SAhmet Inan if (error) 3617e577a17SAhmet Inan return error; 3627e577a17SAhmet Inan 3637e577a17SAhmet Inan error = input_register_device(input); 3647e577a17SAhmet Inan if (error) 3657e577a17SAhmet Inan return error; 3667e577a17SAhmet Inan 3677e577a17SAhmet Inan error = devm_request_threaded_irq(&client->dev, client->irq, 3687e577a17SAhmet Inan NULL, exc3000_interrupt, IRQF_ONESHOT, 3697e577a17SAhmet Inan client->name, data); 3707e577a17SAhmet Inan if (error) 3717e577a17SAhmet Inan return error; 3727e577a17SAhmet Inan 373*d862a306SSebastian Reichel /* 374*d862a306SSebastian Reichel * I²C does not have built-in recovery, so retry on failure. This 375*d862a306SSebastian Reichel * ensures, that the device probe will not fail for temporary issues 376*d862a306SSebastian Reichel * on the bus. This is not needed for the sysfs calls (userspace 377*d862a306SSebastian Reichel * will receive the error code and can start another query) and 378*d862a306SSebastian Reichel * cannot be done for touch events (but that only means loosing one 379*d862a306SSebastian Reichel * or two touch events anyways). 380*d862a306SSebastian Reichel */ 381*d862a306SSebastian Reichel for (retry = 0; retry < 3; retry++) { 382*d862a306SSebastian Reichel error = exc3000_get_model(data); 383*d862a306SSebastian Reichel if (!error) 384*d862a306SSebastian Reichel break; 385*d862a306SSebastian Reichel dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n", 386*d862a306SSebastian Reichel retry + 1, error); 387*d862a306SSebastian Reichel } 388*d862a306SSebastian Reichel 389*d862a306SSebastian Reichel if (error) 390*d862a306SSebastian Reichel return error; 391*d862a306SSebastian Reichel 392*d862a306SSebastian Reichel dev_dbg(&client->dev, "TS Model: %s", data->model); 393*d862a306SSebastian Reichel 394*d862a306SSebastian Reichel i2c_set_clientdata(client, data); 395*d862a306SSebastian Reichel 396*d862a306SSebastian Reichel error = devm_device_add_group(&client->dev, &exc3000_attribute_group); 397*d862a306SSebastian Reichel if (error) 398*d862a306SSebastian Reichel return error; 399*d862a306SSebastian Reichel 4007e577a17SAhmet Inan return 0; 4017e577a17SAhmet Inan } 4027e577a17SAhmet Inan 4037e577a17SAhmet Inan static const struct i2c_device_id exc3000_id[] = { 4043bdd21c6SSebastian Reichel { "exc3000", EETI_EXC3000 }, 4053bdd21c6SSebastian Reichel { "exc80h60", EETI_EXC80H60 }, 4063bdd21c6SSebastian Reichel { "exc80h84", EETI_EXC80H84 }, 4077e577a17SAhmet Inan { } 4087e577a17SAhmet Inan }; 4097e577a17SAhmet Inan MODULE_DEVICE_TABLE(i2c, exc3000_id); 4107e577a17SAhmet Inan 4117e577a17SAhmet Inan #ifdef CONFIG_OF 4127e577a17SAhmet Inan static const struct of_device_id exc3000_of_match[] = { 4133bdd21c6SSebastian Reichel { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] }, 4143bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] }, 4153bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] }, 4167e577a17SAhmet Inan { } 4177e577a17SAhmet Inan }; 4187e577a17SAhmet Inan MODULE_DEVICE_TABLE(of, exc3000_of_match); 4197e577a17SAhmet Inan #endif 4207e577a17SAhmet Inan 4217e577a17SAhmet Inan static struct i2c_driver exc3000_driver = { 4227e577a17SAhmet Inan .driver = { 4237e577a17SAhmet Inan .name = "exc3000", 4247e577a17SAhmet Inan .of_match_table = of_match_ptr(exc3000_of_match), 4257e577a17SAhmet Inan }, 4267e577a17SAhmet Inan .id_table = exc3000_id, 427deae5764SSebastian Reichel .probe_new = exc3000_probe, 4287e577a17SAhmet Inan }; 4297e577a17SAhmet Inan 4307e577a17SAhmet Inan module_i2c_driver(exc3000_driver); 4317e577a17SAhmet Inan 4327e577a17SAhmet Inan MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); 4337e577a17SAhmet Inan MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); 4347e577a17SAhmet Inan MODULE_LICENSE("GPL v2"); 435