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 30d862a306SSebastian Reichel #define EXC3000_LEN_MODEL_NAME 16 31d862a306SSebastian Reichel #define EXC3000_LEN_FW_VERSION 16 32d862a306SSebastian Reichel 33*a63d0120SLucas Stach #define EXC3000_VENDOR_EVENT 0x03 343bdd21c6SSebastian Reichel #define EXC3000_MT1_EVENT 0x06 353bdd21c6SSebastian Reichel #define EXC3000_MT2_EVENT 0x18 363bdd21c6SSebastian Reichel 377e577a17SAhmet Inan #define EXC3000_TIMEOUT_MS 100 387e577a17SAhmet Inan 3927aced19SSebastian Reichel #define EXC3000_RESET_MS 10 4027aced19SSebastian Reichel #define EXC3000_READY_MS 100 4127aced19SSebastian Reichel 423bdd21c6SSebastian Reichel static const struct i2c_device_id exc3000_id[]; 433bdd21c6SSebastian Reichel 443bdd21c6SSebastian Reichel struct eeti_dev_info { 453bdd21c6SSebastian Reichel const char *name; 463bdd21c6SSebastian Reichel int max_xy; 473bdd21c6SSebastian Reichel }; 483bdd21c6SSebastian Reichel 493bdd21c6SSebastian Reichel enum eeti_dev_id { 503bdd21c6SSebastian Reichel EETI_EXC3000, 513bdd21c6SSebastian Reichel EETI_EXC80H60, 523bdd21c6SSebastian Reichel EETI_EXC80H84, 533bdd21c6SSebastian Reichel }; 543bdd21c6SSebastian Reichel 553bdd21c6SSebastian Reichel static struct eeti_dev_info exc3000_info[] = { 563bdd21c6SSebastian Reichel [EETI_EXC3000] = { 573bdd21c6SSebastian Reichel .name = "EETI EXC3000 Touch Screen", 583bdd21c6SSebastian Reichel .max_xy = SZ_4K - 1, 593bdd21c6SSebastian Reichel }, 603bdd21c6SSebastian Reichel [EETI_EXC80H60] = { 613bdd21c6SSebastian Reichel .name = "EETI EXC80H60 Touch Screen", 623bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 633bdd21c6SSebastian Reichel }, 643bdd21c6SSebastian Reichel [EETI_EXC80H84] = { 653bdd21c6SSebastian Reichel .name = "EETI EXC80H84 Touch Screen", 663bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 673bdd21c6SSebastian Reichel }, 683bdd21c6SSebastian Reichel }; 693bdd21c6SSebastian Reichel 707e577a17SAhmet Inan struct exc3000_data { 717e577a17SAhmet Inan struct i2c_client *client; 723bdd21c6SSebastian Reichel const struct eeti_dev_info *info; 737e577a17SAhmet Inan struct input_dev *input; 747e577a17SAhmet Inan struct touchscreen_properties prop; 7527aced19SSebastian Reichel struct gpio_desc *reset; 767e577a17SAhmet Inan struct timer_list timer; 777e577a17SAhmet Inan u8 buf[2 * EXC3000_LEN_FRAME]; 78d862a306SSebastian Reichel struct completion wait_event; 79d862a306SSebastian Reichel struct mutex query_lock; 80d862a306SSebastian Reichel int query_result; 81d862a306SSebastian Reichel char model[EXC3000_LEN_MODEL_NAME]; 82d862a306SSebastian Reichel char fw_version[EXC3000_LEN_FW_VERSION]; 837e577a17SAhmet Inan }; 847e577a17SAhmet Inan 857e577a17SAhmet Inan static void exc3000_report_slots(struct input_dev *input, 867e577a17SAhmet Inan struct touchscreen_properties *prop, 877e577a17SAhmet Inan const u8 *buf, int num) 887e577a17SAhmet Inan { 897e577a17SAhmet Inan for (; num--; buf += EXC3000_LEN_POINT) { 907e577a17SAhmet Inan if (buf[0] & BIT(0)) { 917e577a17SAhmet Inan input_mt_slot(input, buf[1]); 927e577a17SAhmet Inan input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 937e577a17SAhmet Inan touchscreen_report_pos(input, prop, 947e577a17SAhmet Inan get_unaligned_le16(buf + 2), 957e577a17SAhmet Inan get_unaligned_le16(buf + 4), 967e577a17SAhmet Inan true); 977e577a17SAhmet Inan } 987e577a17SAhmet Inan } 997e577a17SAhmet Inan } 1007e577a17SAhmet Inan 1017e577a17SAhmet Inan static void exc3000_timer(struct timer_list *t) 1027e577a17SAhmet Inan { 1037e577a17SAhmet Inan struct exc3000_data *data = from_timer(data, t, timer); 1047e577a17SAhmet Inan 1057e577a17SAhmet Inan input_mt_sync_frame(data->input); 1067e577a17SAhmet Inan input_sync(data->input); 1077e577a17SAhmet Inan } 1087e577a17SAhmet Inan 109*a63d0120SLucas Stach static inline void exc3000_schedule_timer(struct exc3000_data *data) 110*a63d0120SLucas Stach { 111*a63d0120SLucas Stach mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); 112*a63d0120SLucas Stach } 113*a63d0120SLucas Stach 1143bdd21c6SSebastian Reichel static int exc3000_read_frame(struct exc3000_data *data, u8 *buf) 1157e577a17SAhmet Inan { 1163bdd21c6SSebastian Reichel struct i2c_client *client = data->client; 1177e577a17SAhmet Inan int ret; 1187e577a17SAhmet Inan 1197e577a17SAhmet Inan ret = i2c_master_send(client, "'", 2); 1207e577a17SAhmet Inan if (ret < 0) 1217e577a17SAhmet Inan return ret; 1227e577a17SAhmet Inan 1237e577a17SAhmet Inan if (ret != 2) 1247e577a17SAhmet Inan return -EIO; 1257e577a17SAhmet Inan 1267e577a17SAhmet Inan ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME); 1277e577a17SAhmet Inan if (ret < 0) 1287e577a17SAhmet Inan return ret; 1297e577a17SAhmet Inan 1307e577a17SAhmet Inan if (ret != EXC3000_LEN_FRAME) 1317e577a17SAhmet Inan return -EIO; 1327e577a17SAhmet Inan 1333bdd21c6SSebastian Reichel if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME) 1343bdd21c6SSebastian Reichel return -EINVAL; 1353bdd21c6SSebastian Reichel 1367e577a17SAhmet Inan return 0; 1377e577a17SAhmet Inan } 1387e577a17SAhmet Inan 139*a63d0120SLucas Stach static int exc3000_handle_mt_event(struct exc3000_data *data) 1407e577a17SAhmet Inan { 141*a63d0120SLucas Stach struct input_dev *input = data->input; 142*a63d0120SLucas Stach int ret, total_slots; 143*a63d0120SLucas Stach u8 *buf = data->buf; 1447e577a17SAhmet Inan 145*a63d0120SLucas Stach total_slots = buf[3]; 146*a63d0120SLucas Stach if (!total_slots || total_slots > EXC3000_NUM_SLOTS) { 147*a63d0120SLucas Stach ret = -EINVAL; 148*a63d0120SLucas Stach goto out_fail; 149*a63d0120SLucas Stach } 1507e577a17SAhmet Inan 151*a63d0120SLucas Stach if (total_slots > EXC3000_SLOTS_PER_FRAME) { 1527e577a17SAhmet Inan /* Read 2nd frame to get the rest of the contacts. */ 153*a63d0120SLucas Stach ret = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME); 154*a63d0120SLucas Stach if (ret) 155*a63d0120SLucas Stach goto out_fail; 1567e577a17SAhmet Inan 1577e577a17SAhmet Inan /* 2nd chunk must have number of contacts set to 0. */ 158*a63d0120SLucas Stach if (buf[EXC3000_LEN_FRAME + 3] != 0) { 159*a63d0120SLucas Stach ret = -EINVAL; 160*a63d0120SLucas Stach goto out_fail; 161*a63d0120SLucas Stach } 1627e577a17SAhmet Inan } 1637e577a17SAhmet Inan 164*a63d0120SLucas Stach /* 165*a63d0120SLucas Stach * We read full state successfully, no contacts will be "stuck". 166*a63d0120SLucas Stach */ 167*a63d0120SLucas Stach del_timer_sync(&data->timer); 168*a63d0120SLucas Stach 169*a63d0120SLucas Stach while (total_slots > 0) { 170*a63d0120SLucas Stach int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); 171*a63d0120SLucas Stach 172*a63d0120SLucas Stach exc3000_report_slots(input, &data->prop, buf + 4, slots); 173*a63d0120SLucas Stach total_slots -= slots; 174*a63d0120SLucas Stach buf += EXC3000_LEN_FRAME; 175*a63d0120SLucas Stach } 176*a63d0120SLucas Stach 177*a63d0120SLucas Stach input_mt_sync_frame(input); 178*a63d0120SLucas Stach input_sync(input); 179*a63d0120SLucas Stach 1807e577a17SAhmet Inan return 0; 181*a63d0120SLucas Stach 182*a63d0120SLucas Stach out_fail: 183*a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 184*a63d0120SLucas Stach exc3000_schedule_timer(data); 185*a63d0120SLucas Stach 186*a63d0120SLucas Stach return ret; 1877e577a17SAhmet Inan } 1887e577a17SAhmet Inan 189d862a306SSebastian Reichel static int exc3000_query_interrupt(struct exc3000_data *data) 190d862a306SSebastian Reichel { 191d862a306SSebastian Reichel u8 *buf = data->buf; 192d862a306SSebastian Reichel 193d862a306SSebastian Reichel if (buf[0] != 'B') 194d862a306SSebastian Reichel return -EPROTO; 195d862a306SSebastian Reichel 196d862a306SSebastian Reichel if (buf[4] == 'E') 197d862a306SSebastian Reichel strlcpy(data->model, buf + 5, sizeof(data->model)); 198d862a306SSebastian Reichel else if (buf[4] == 'D') 199d862a306SSebastian Reichel strlcpy(data->fw_version, buf + 5, sizeof(data->fw_version)); 200d862a306SSebastian Reichel else 201d862a306SSebastian Reichel return -EPROTO; 202d862a306SSebastian Reichel 203d862a306SSebastian Reichel return 0; 204d862a306SSebastian Reichel } 205d862a306SSebastian Reichel 2067e577a17SAhmet Inan static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 2077e577a17SAhmet Inan { 2087e577a17SAhmet Inan struct exc3000_data *data = dev_id; 2097e577a17SAhmet Inan u8 *buf = data->buf; 210*a63d0120SLucas Stach int ret; 2117e577a17SAhmet Inan 212*a63d0120SLucas Stach ret = exc3000_read_frame(data, buf); 213*a63d0120SLucas Stach if (ret) { 214*a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 215*a63d0120SLucas Stach exc3000_schedule_timer(data); 216*a63d0120SLucas Stach goto out; 217*a63d0120SLucas Stach } 218*a63d0120SLucas Stach 219*a63d0120SLucas Stach switch (buf[2]) { 220*a63d0120SLucas Stach case EXC3000_VENDOR_EVENT: 221d862a306SSebastian Reichel data->query_result = exc3000_query_interrupt(data); 222d862a306SSebastian Reichel complete(&data->wait_event); 223*a63d0120SLucas Stach break; 224*a63d0120SLucas Stach 225*a63d0120SLucas Stach case EXC3000_MT1_EVENT: 226*a63d0120SLucas Stach case EXC3000_MT2_EVENT: 227*a63d0120SLucas Stach exc3000_handle_mt_event(data); 228*a63d0120SLucas Stach break; 229*a63d0120SLucas Stach 230*a63d0120SLucas Stach default: 231*a63d0120SLucas Stach break; 232d862a306SSebastian Reichel } 233d862a306SSebastian Reichel 2347e577a17SAhmet Inan out: 2357e577a17SAhmet Inan return IRQ_HANDLED; 2367e577a17SAhmet Inan } 2377e577a17SAhmet Inan 238d862a306SSebastian Reichel static ssize_t fw_version_show(struct device *dev, 239d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 240d862a306SSebastian Reichel { 241d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 242d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 243d862a306SSebastian Reichel static const u8 request[68] = { 244d862a306SSebastian Reichel 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'D', 0x00 245d862a306SSebastian Reichel }; 246d862a306SSebastian Reichel int error; 247d862a306SSebastian Reichel 248d862a306SSebastian Reichel mutex_lock(&data->query_lock); 249d862a306SSebastian Reichel 250d862a306SSebastian Reichel data->query_result = -ETIMEDOUT; 251d862a306SSebastian Reichel reinit_completion(&data->wait_event); 252d862a306SSebastian Reichel 253d862a306SSebastian Reichel error = i2c_master_send(client, request, sizeof(request)); 254d862a306SSebastian Reichel if (error < 0) { 255d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 256d862a306SSebastian Reichel return error; 257d862a306SSebastian Reichel } 258d862a306SSebastian Reichel 259d862a306SSebastian Reichel wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 260d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 261d862a306SSebastian Reichel 262d862a306SSebastian Reichel if (data->query_result < 0) 263d862a306SSebastian Reichel return data->query_result; 264d862a306SSebastian Reichel 265d862a306SSebastian Reichel return sprintf(buf, "%s\n", data->fw_version); 266d862a306SSebastian Reichel } 267d862a306SSebastian Reichel static DEVICE_ATTR_RO(fw_version); 268d862a306SSebastian Reichel 269d862a306SSebastian Reichel static ssize_t exc3000_get_model(struct exc3000_data *data) 270d862a306SSebastian Reichel { 271d862a306SSebastian Reichel static const u8 request[68] = { 272d862a306SSebastian Reichel 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00 273d862a306SSebastian Reichel }; 274d862a306SSebastian Reichel struct i2c_client *client = data->client; 275d862a306SSebastian Reichel int error; 276d862a306SSebastian Reichel 277d862a306SSebastian Reichel mutex_lock(&data->query_lock); 278d862a306SSebastian Reichel data->query_result = -ETIMEDOUT; 279d862a306SSebastian Reichel reinit_completion(&data->wait_event); 280d862a306SSebastian Reichel 281d862a306SSebastian Reichel error = i2c_master_send(client, request, sizeof(request)); 282d862a306SSebastian Reichel if (error < 0) { 283d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 284d862a306SSebastian Reichel return error; 285d862a306SSebastian Reichel } 286d862a306SSebastian Reichel 287d862a306SSebastian Reichel wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ); 288d862a306SSebastian Reichel mutex_unlock(&data->query_lock); 289d862a306SSebastian Reichel 290d862a306SSebastian Reichel return data->query_result; 291d862a306SSebastian Reichel } 292d862a306SSebastian Reichel 293d862a306SSebastian Reichel static ssize_t model_show(struct device *dev, 294d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 295d862a306SSebastian Reichel { 296d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 297d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 298d862a306SSebastian Reichel int error; 299d862a306SSebastian Reichel 300d862a306SSebastian Reichel error = exc3000_get_model(data); 301d862a306SSebastian Reichel if (error < 0) 302d862a306SSebastian Reichel return error; 303d862a306SSebastian Reichel 304d862a306SSebastian Reichel return sprintf(buf, "%s\n", data->model); 305d862a306SSebastian Reichel } 306d862a306SSebastian Reichel static DEVICE_ATTR_RO(model); 307d862a306SSebastian Reichel 308d862a306SSebastian Reichel static struct attribute *sysfs_attrs[] = { 309d862a306SSebastian Reichel &dev_attr_fw_version.attr, 310d862a306SSebastian Reichel &dev_attr_model.attr, 311d862a306SSebastian Reichel NULL 312d862a306SSebastian Reichel }; 313d862a306SSebastian Reichel 314d862a306SSebastian Reichel static struct attribute_group exc3000_attribute_group = { 315d862a306SSebastian Reichel .attrs = sysfs_attrs 316d862a306SSebastian Reichel }; 317d862a306SSebastian Reichel 318deae5764SSebastian Reichel static int exc3000_probe(struct i2c_client *client) 3197e577a17SAhmet Inan { 3207e577a17SAhmet Inan struct exc3000_data *data; 3217e577a17SAhmet Inan struct input_dev *input; 322d862a306SSebastian Reichel int error, max_xy, retry; 3237e577a17SAhmet Inan 3247e577a17SAhmet Inan data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 3257e577a17SAhmet Inan if (!data) 3267e577a17SAhmet Inan return -ENOMEM; 3277e577a17SAhmet Inan 3287e577a17SAhmet Inan data->client = client; 3293bdd21c6SSebastian Reichel data->info = device_get_match_data(&client->dev); 3303bdd21c6SSebastian Reichel if (!data->info) { 3313bdd21c6SSebastian Reichel enum eeti_dev_id eeti_dev_id = 3323bdd21c6SSebastian Reichel i2c_match_id(exc3000_id, client)->driver_data; 3333bdd21c6SSebastian Reichel data->info = &exc3000_info[eeti_dev_id]; 3343bdd21c6SSebastian Reichel } 3357e577a17SAhmet Inan timer_setup(&data->timer, exc3000_timer, 0); 336d862a306SSebastian Reichel init_completion(&data->wait_event); 337d862a306SSebastian Reichel mutex_init(&data->query_lock); 3387e577a17SAhmet Inan 33927aced19SSebastian Reichel data->reset = devm_gpiod_get_optional(&client->dev, "reset", 34027aced19SSebastian Reichel GPIOD_OUT_HIGH); 34127aced19SSebastian Reichel if (IS_ERR(data->reset)) 34227aced19SSebastian Reichel return PTR_ERR(data->reset); 34327aced19SSebastian Reichel 34427aced19SSebastian Reichel if (data->reset) { 34527aced19SSebastian Reichel msleep(EXC3000_RESET_MS); 34627aced19SSebastian Reichel gpiod_set_value_cansleep(data->reset, 0); 34727aced19SSebastian Reichel msleep(EXC3000_READY_MS); 34827aced19SSebastian Reichel } 34927aced19SSebastian Reichel 3507e577a17SAhmet Inan input = devm_input_allocate_device(&client->dev); 3517e577a17SAhmet Inan if (!input) 3527e577a17SAhmet Inan return -ENOMEM; 3537e577a17SAhmet Inan 3547e577a17SAhmet Inan data->input = input; 355d862a306SSebastian Reichel input_set_drvdata(input, data); 3567e577a17SAhmet Inan 3573bdd21c6SSebastian Reichel input->name = data->info->name; 3587e577a17SAhmet Inan input->id.bustype = BUS_I2C; 3597e577a17SAhmet Inan 3603bdd21c6SSebastian Reichel max_xy = data->info->max_xy; 3613bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 3623bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 3633bdd21c6SSebastian Reichel 3647e577a17SAhmet Inan touchscreen_parse_properties(input, true, &data->prop); 3657e577a17SAhmet Inan 3667e577a17SAhmet Inan error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, 3677e577a17SAhmet Inan INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 3687e577a17SAhmet Inan if (error) 3697e577a17SAhmet Inan return error; 3707e577a17SAhmet Inan 3717e577a17SAhmet Inan error = input_register_device(input); 3727e577a17SAhmet Inan if (error) 3737e577a17SAhmet Inan return error; 3747e577a17SAhmet Inan 3757e577a17SAhmet Inan error = devm_request_threaded_irq(&client->dev, client->irq, 3767e577a17SAhmet Inan NULL, exc3000_interrupt, IRQF_ONESHOT, 3777e577a17SAhmet Inan client->name, data); 3787e577a17SAhmet Inan if (error) 3797e577a17SAhmet Inan return error; 3807e577a17SAhmet Inan 381d862a306SSebastian Reichel /* 382d862a306SSebastian Reichel * I²C does not have built-in recovery, so retry on failure. This 383d862a306SSebastian Reichel * ensures, that the device probe will not fail for temporary issues 384d862a306SSebastian Reichel * on the bus. This is not needed for the sysfs calls (userspace 385d862a306SSebastian Reichel * will receive the error code and can start another query) and 386d862a306SSebastian Reichel * cannot be done for touch events (but that only means loosing one 387d862a306SSebastian Reichel * or two touch events anyways). 388d862a306SSebastian Reichel */ 389d862a306SSebastian Reichel for (retry = 0; retry < 3; retry++) { 390d862a306SSebastian Reichel error = exc3000_get_model(data); 391d862a306SSebastian Reichel if (!error) 392d862a306SSebastian Reichel break; 393d862a306SSebastian Reichel dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n", 394d862a306SSebastian Reichel retry + 1, error); 395d862a306SSebastian Reichel } 396d862a306SSebastian Reichel 397d862a306SSebastian Reichel if (error) 398d862a306SSebastian Reichel return error; 399d862a306SSebastian Reichel 400d862a306SSebastian Reichel dev_dbg(&client->dev, "TS Model: %s", data->model); 401d862a306SSebastian Reichel 402d862a306SSebastian Reichel i2c_set_clientdata(client, data); 403d862a306SSebastian Reichel 404d862a306SSebastian Reichel error = devm_device_add_group(&client->dev, &exc3000_attribute_group); 405d862a306SSebastian Reichel if (error) 406d862a306SSebastian Reichel return error; 407d862a306SSebastian Reichel 4087e577a17SAhmet Inan return 0; 4097e577a17SAhmet Inan } 4107e577a17SAhmet Inan 4117e577a17SAhmet Inan static const struct i2c_device_id exc3000_id[] = { 4123bdd21c6SSebastian Reichel { "exc3000", EETI_EXC3000 }, 4133bdd21c6SSebastian Reichel { "exc80h60", EETI_EXC80H60 }, 4143bdd21c6SSebastian Reichel { "exc80h84", EETI_EXC80H84 }, 4157e577a17SAhmet Inan { } 4167e577a17SAhmet Inan }; 4177e577a17SAhmet Inan MODULE_DEVICE_TABLE(i2c, exc3000_id); 4187e577a17SAhmet Inan 4197e577a17SAhmet Inan #ifdef CONFIG_OF 4207e577a17SAhmet Inan static const struct of_device_id exc3000_of_match[] = { 4213bdd21c6SSebastian Reichel { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] }, 4223bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] }, 4233bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] }, 4247e577a17SAhmet Inan { } 4257e577a17SAhmet Inan }; 4267e577a17SAhmet Inan MODULE_DEVICE_TABLE(of, exc3000_of_match); 4277e577a17SAhmet Inan #endif 4287e577a17SAhmet Inan 4297e577a17SAhmet Inan static struct i2c_driver exc3000_driver = { 4307e577a17SAhmet Inan .driver = { 4317e577a17SAhmet Inan .name = "exc3000", 4327e577a17SAhmet Inan .of_match_table = of_match_ptr(exc3000_of_match), 4337e577a17SAhmet Inan }, 4347e577a17SAhmet Inan .id_table = exc3000_id, 435deae5764SSebastian Reichel .probe_new = exc3000_probe, 4367e577a17SAhmet Inan }; 4377e577a17SAhmet Inan 4387e577a17SAhmet Inan module_i2c_driver(exc3000_driver); 4397e577a17SAhmet Inan 4407e577a17SAhmet Inan MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); 4417e577a17SAhmet Inan MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); 4427e577a17SAhmet Inan MODULE_LICENSE("GPL v2"); 443