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 28*102feb1dSLucas Stach #define EXC3000_LEN_VENDOR_REQUEST 68 297e577a17SAhmet Inan #define EXC3000_LEN_POINT 10 303bdd21c6SSebastian Reichel 31d862a306SSebastian Reichel #define EXC3000_LEN_MODEL_NAME 16 32d862a306SSebastian Reichel #define EXC3000_LEN_FW_VERSION 16 33d862a306SSebastian Reichel 34a63d0120SLucas Stach #define EXC3000_VENDOR_EVENT 0x03 353bdd21c6SSebastian Reichel #define EXC3000_MT1_EVENT 0x06 363bdd21c6SSebastian Reichel #define EXC3000_MT2_EVENT 0x18 373bdd21c6SSebastian Reichel 387e577a17SAhmet Inan #define EXC3000_TIMEOUT_MS 100 397e577a17SAhmet Inan 4027aced19SSebastian Reichel #define EXC3000_RESET_MS 10 4127aced19SSebastian Reichel #define EXC3000_READY_MS 100 4227aced19SSebastian Reichel 433bdd21c6SSebastian Reichel static const struct i2c_device_id exc3000_id[]; 443bdd21c6SSebastian Reichel 453bdd21c6SSebastian Reichel struct eeti_dev_info { 463bdd21c6SSebastian Reichel const char *name; 473bdd21c6SSebastian Reichel int max_xy; 483bdd21c6SSebastian Reichel }; 493bdd21c6SSebastian Reichel 503bdd21c6SSebastian Reichel enum eeti_dev_id { 513bdd21c6SSebastian Reichel EETI_EXC3000, 523bdd21c6SSebastian Reichel EETI_EXC80H60, 533bdd21c6SSebastian Reichel EETI_EXC80H84, 543bdd21c6SSebastian Reichel }; 553bdd21c6SSebastian Reichel 563bdd21c6SSebastian Reichel static struct eeti_dev_info exc3000_info[] = { 573bdd21c6SSebastian Reichel [EETI_EXC3000] = { 583bdd21c6SSebastian Reichel .name = "EETI EXC3000 Touch Screen", 593bdd21c6SSebastian Reichel .max_xy = SZ_4K - 1, 603bdd21c6SSebastian Reichel }, 613bdd21c6SSebastian Reichel [EETI_EXC80H60] = { 623bdd21c6SSebastian Reichel .name = "EETI EXC80H60 Touch Screen", 633bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 643bdd21c6SSebastian Reichel }, 653bdd21c6SSebastian Reichel [EETI_EXC80H84] = { 663bdd21c6SSebastian Reichel .name = "EETI EXC80H84 Touch Screen", 673bdd21c6SSebastian Reichel .max_xy = SZ_16K - 1, 683bdd21c6SSebastian Reichel }, 693bdd21c6SSebastian Reichel }; 703bdd21c6SSebastian Reichel 717e577a17SAhmet Inan struct exc3000_data { 727e577a17SAhmet Inan struct i2c_client *client; 733bdd21c6SSebastian Reichel const struct eeti_dev_info *info; 747e577a17SAhmet Inan struct input_dev *input; 757e577a17SAhmet Inan struct touchscreen_properties prop; 7627aced19SSebastian Reichel struct gpio_desc *reset; 777e577a17SAhmet Inan struct timer_list timer; 787e577a17SAhmet Inan u8 buf[2 * EXC3000_LEN_FRAME]; 79d862a306SSebastian Reichel struct completion wait_event; 80d862a306SSebastian Reichel struct mutex query_lock; 817e577a17SAhmet Inan }; 827e577a17SAhmet Inan 837e577a17SAhmet Inan static void exc3000_report_slots(struct input_dev *input, 847e577a17SAhmet Inan struct touchscreen_properties *prop, 857e577a17SAhmet Inan const u8 *buf, int num) 867e577a17SAhmet Inan { 877e577a17SAhmet Inan for (; num--; buf += EXC3000_LEN_POINT) { 887e577a17SAhmet Inan if (buf[0] & BIT(0)) { 897e577a17SAhmet Inan input_mt_slot(input, buf[1]); 907e577a17SAhmet Inan input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 917e577a17SAhmet Inan touchscreen_report_pos(input, prop, 927e577a17SAhmet Inan get_unaligned_le16(buf + 2), 937e577a17SAhmet Inan get_unaligned_le16(buf + 4), 947e577a17SAhmet Inan true); 957e577a17SAhmet Inan } 967e577a17SAhmet Inan } 977e577a17SAhmet Inan } 987e577a17SAhmet Inan 997e577a17SAhmet Inan static void exc3000_timer(struct timer_list *t) 1007e577a17SAhmet Inan { 1017e577a17SAhmet Inan struct exc3000_data *data = from_timer(data, t, timer); 1027e577a17SAhmet Inan 1037e577a17SAhmet Inan input_mt_sync_frame(data->input); 1047e577a17SAhmet Inan input_sync(data->input); 1057e577a17SAhmet Inan } 1067e577a17SAhmet Inan 107a63d0120SLucas Stach static inline void exc3000_schedule_timer(struct exc3000_data *data) 108a63d0120SLucas Stach { 109a63d0120SLucas Stach mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); 110a63d0120SLucas Stach } 111a63d0120SLucas Stach 1123bdd21c6SSebastian Reichel static int exc3000_read_frame(struct exc3000_data *data, u8 *buf) 1137e577a17SAhmet Inan { 1143bdd21c6SSebastian Reichel struct i2c_client *client = data->client; 1157e577a17SAhmet Inan int ret; 1167e577a17SAhmet Inan 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 1347e577a17SAhmet Inan return 0; 1357e577a17SAhmet Inan } 1367e577a17SAhmet Inan 137a63d0120SLucas Stach static int exc3000_handle_mt_event(struct exc3000_data *data) 1387e577a17SAhmet Inan { 139a63d0120SLucas Stach struct input_dev *input = data->input; 140a63d0120SLucas Stach int ret, total_slots; 141a63d0120SLucas Stach u8 *buf = data->buf; 1427e577a17SAhmet Inan 143a63d0120SLucas Stach total_slots = buf[3]; 144a63d0120SLucas Stach if (!total_slots || total_slots > EXC3000_NUM_SLOTS) { 145a63d0120SLucas Stach ret = -EINVAL; 146a63d0120SLucas Stach goto out_fail; 147a63d0120SLucas Stach } 1487e577a17SAhmet Inan 149a63d0120SLucas Stach if (total_slots > EXC3000_SLOTS_PER_FRAME) { 1507e577a17SAhmet Inan /* Read 2nd frame to get the rest of the contacts. */ 151a63d0120SLucas Stach ret = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME); 152a63d0120SLucas Stach if (ret) 153a63d0120SLucas Stach goto out_fail; 1547e577a17SAhmet Inan 1557e577a17SAhmet Inan /* 2nd chunk must have number of contacts set to 0. */ 156a63d0120SLucas Stach if (buf[EXC3000_LEN_FRAME + 3] != 0) { 157a63d0120SLucas Stach ret = -EINVAL; 158a63d0120SLucas Stach goto out_fail; 159a63d0120SLucas Stach } 1607e577a17SAhmet Inan } 1617e577a17SAhmet Inan 162a63d0120SLucas Stach /* 163a63d0120SLucas Stach * We read full state successfully, no contacts will be "stuck". 164a63d0120SLucas Stach */ 165a63d0120SLucas Stach del_timer_sync(&data->timer); 166a63d0120SLucas Stach 167a63d0120SLucas Stach while (total_slots > 0) { 168a63d0120SLucas Stach int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); 169a63d0120SLucas Stach 170a63d0120SLucas Stach exc3000_report_slots(input, &data->prop, buf + 4, slots); 171a63d0120SLucas Stach total_slots -= slots; 172a63d0120SLucas Stach buf += EXC3000_LEN_FRAME; 173a63d0120SLucas Stach } 174a63d0120SLucas Stach 175a63d0120SLucas Stach input_mt_sync_frame(input); 176a63d0120SLucas Stach input_sync(input); 177a63d0120SLucas Stach 1787e577a17SAhmet Inan return 0; 179a63d0120SLucas Stach 180a63d0120SLucas Stach out_fail: 181a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 182a63d0120SLucas Stach exc3000_schedule_timer(data); 183a63d0120SLucas Stach 184a63d0120SLucas Stach return ret; 1857e577a17SAhmet Inan } 1867e577a17SAhmet Inan 1877e577a17SAhmet Inan static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 1887e577a17SAhmet Inan { 1897e577a17SAhmet Inan struct exc3000_data *data = dev_id; 1907e577a17SAhmet Inan u8 *buf = data->buf; 191a63d0120SLucas Stach int ret; 1927e577a17SAhmet Inan 193a63d0120SLucas Stach ret = exc3000_read_frame(data, buf); 194a63d0120SLucas Stach if (ret) { 195a63d0120SLucas Stach /* Schedule a timer to release "stuck" contacts */ 196a63d0120SLucas Stach exc3000_schedule_timer(data); 197a63d0120SLucas Stach goto out; 198a63d0120SLucas Stach } 199a63d0120SLucas Stach 200a63d0120SLucas Stach switch (buf[2]) { 201a63d0120SLucas Stach case EXC3000_VENDOR_EVENT: 202d862a306SSebastian Reichel complete(&data->wait_event); 203a63d0120SLucas Stach break; 204a63d0120SLucas Stach 205a63d0120SLucas Stach case EXC3000_MT1_EVENT: 206a63d0120SLucas Stach case EXC3000_MT2_EVENT: 207a63d0120SLucas Stach exc3000_handle_mt_event(data); 208a63d0120SLucas Stach break; 209a63d0120SLucas Stach 210a63d0120SLucas Stach default: 211a63d0120SLucas Stach break; 212d862a306SSebastian Reichel } 213d862a306SSebastian Reichel 2147e577a17SAhmet Inan out: 2157e577a17SAhmet Inan return IRQ_HANDLED; 2167e577a17SAhmet Inan } 2177e577a17SAhmet Inan 218*102feb1dSLucas Stach static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, 219*102feb1dSLucas Stach u8 request_len, u8 *response, int timeout) 220*102feb1dSLucas Stach { 221*102feb1dSLucas Stach u8 buf[EXC3000_LEN_VENDOR_REQUEST] = { 0x67, 0x00, 0x42, 0x00, 0x03 }; 222*102feb1dSLucas Stach int ret; 223*102feb1dSLucas Stach 224*102feb1dSLucas Stach mutex_lock(&data->query_lock); 225*102feb1dSLucas Stach 226*102feb1dSLucas Stach reinit_completion(&data->wait_event); 227*102feb1dSLucas Stach 228*102feb1dSLucas Stach buf[5] = request_len; 229*102feb1dSLucas Stach memcpy(&buf[6], request, request_len); 230*102feb1dSLucas Stach 231*102feb1dSLucas Stach ret = i2c_master_send(data->client, buf, EXC3000_LEN_VENDOR_REQUEST); 232*102feb1dSLucas Stach if (ret < 0) 233*102feb1dSLucas Stach goto out_unlock; 234*102feb1dSLucas Stach 235*102feb1dSLucas Stach if (response) { 236*102feb1dSLucas Stach ret = wait_for_completion_timeout(&data->wait_event, 237*102feb1dSLucas Stach timeout * HZ); 238*102feb1dSLucas Stach if (ret <= 0) { 239*102feb1dSLucas Stach ret = -ETIMEDOUT; 240*102feb1dSLucas Stach goto out_unlock; 241*102feb1dSLucas Stach } 242*102feb1dSLucas Stach 243*102feb1dSLucas Stach if (data->buf[3] >= EXC3000_LEN_FRAME) { 244*102feb1dSLucas Stach ret = -ENOSPC; 245*102feb1dSLucas Stach goto out_unlock; 246*102feb1dSLucas Stach } 247*102feb1dSLucas Stach 248*102feb1dSLucas Stach memcpy(response, &data->buf[4], data->buf[3]); 249*102feb1dSLucas Stach ret = data->buf[3]; 250*102feb1dSLucas Stach } 251*102feb1dSLucas Stach 252*102feb1dSLucas Stach out_unlock: 253*102feb1dSLucas Stach mutex_unlock(&data->query_lock); 254*102feb1dSLucas Stach 255*102feb1dSLucas Stach return ret; 256*102feb1dSLucas Stach } 257*102feb1dSLucas Stach 258d862a306SSebastian Reichel static ssize_t fw_version_show(struct device *dev, 259d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 260d862a306SSebastian Reichel { 261d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 262d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 263*102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 264*102feb1dSLucas Stach int ret; 265d862a306SSebastian Reichel 266*102feb1dSLucas Stach ret = exc3000_vendor_data_request(data, (u8[]){'D'}, 1, response, 1); 267*102feb1dSLucas Stach if (ret < 0) 268*102feb1dSLucas Stach return ret; 269d862a306SSebastian Reichel 270*102feb1dSLucas Stach return sprintf(buf, "%s\n", &response[1]); 271d862a306SSebastian Reichel } 272d862a306SSebastian Reichel static DEVICE_ATTR_RO(fw_version); 273d862a306SSebastian Reichel 274d862a306SSebastian Reichel static ssize_t model_show(struct device *dev, 275d862a306SSebastian Reichel struct device_attribute *attr, char *buf) 276d862a306SSebastian Reichel { 277d862a306SSebastian Reichel struct i2c_client *client = to_i2c_client(dev); 278d862a306SSebastian Reichel struct exc3000_data *data = i2c_get_clientdata(client); 279*102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 280*102feb1dSLucas Stach int ret; 281d862a306SSebastian Reichel 282*102feb1dSLucas Stach ret = exc3000_vendor_data_request(data, (u8[]){'E'}, 1, response, 1); 283*102feb1dSLucas Stach if (ret < 0) 284*102feb1dSLucas Stach return ret; 285d862a306SSebastian Reichel 286*102feb1dSLucas Stach return sprintf(buf, "%s\n", &response[1]); 287d862a306SSebastian Reichel } 288d862a306SSebastian Reichel static DEVICE_ATTR_RO(model); 289d862a306SSebastian Reichel 290d862a306SSebastian Reichel static struct attribute *sysfs_attrs[] = { 291d862a306SSebastian Reichel &dev_attr_fw_version.attr, 292d862a306SSebastian Reichel &dev_attr_model.attr, 293d862a306SSebastian Reichel NULL 294d862a306SSebastian Reichel }; 295d862a306SSebastian Reichel 296d862a306SSebastian Reichel static struct attribute_group exc3000_attribute_group = { 297d862a306SSebastian Reichel .attrs = sysfs_attrs 298d862a306SSebastian Reichel }; 299d862a306SSebastian Reichel 300deae5764SSebastian Reichel static int exc3000_probe(struct i2c_client *client) 3017e577a17SAhmet Inan { 3027e577a17SAhmet Inan struct exc3000_data *data; 3037e577a17SAhmet Inan struct input_dev *input; 304d862a306SSebastian Reichel int error, max_xy, retry; 3057e577a17SAhmet Inan 3067e577a17SAhmet Inan data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 3077e577a17SAhmet Inan if (!data) 3087e577a17SAhmet Inan return -ENOMEM; 3097e577a17SAhmet Inan 3107e577a17SAhmet Inan data->client = client; 3113bdd21c6SSebastian Reichel data->info = device_get_match_data(&client->dev); 3123bdd21c6SSebastian Reichel if (!data->info) { 3133bdd21c6SSebastian Reichel enum eeti_dev_id eeti_dev_id = 3143bdd21c6SSebastian Reichel i2c_match_id(exc3000_id, client)->driver_data; 3153bdd21c6SSebastian Reichel data->info = &exc3000_info[eeti_dev_id]; 3163bdd21c6SSebastian Reichel } 3177e577a17SAhmet Inan timer_setup(&data->timer, exc3000_timer, 0); 318d862a306SSebastian Reichel init_completion(&data->wait_event); 319d862a306SSebastian Reichel mutex_init(&data->query_lock); 3207e577a17SAhmet Inan 32127aced19SSebastian Reichel data->reset = devm_gpiod_get_optional(&client->dev, "reset", 32227aced19SSebastian Reichel GPIOD_OUT_HIGH); 32327aced19SSebastian Reichel if (IS_ERR(data->reset)) 32427aced19SSebastian Reichel return PTR_ERR(data->reset); 32527aced19SSebastian Reichel 32627aced19SSebastian Reichel if (data->reset) { 32727aced19SSebastian Reichel msleep(EXC3000_RESET_MS); 32827aced19SSebastian Reichel gpiod_set_value_cansleep(data->reset, 0); 32927aced19SSebastian Reichel msleep(EXC3000_READY_MS); 33027aced19SSebastian Reichel } 33127aced19SSebastian Reichel 3327e577a17SAhmet Inan input = devm_input_allocate_device(&client->dev); 3337e577a17SAhmet Inan if (!input) 3347e577a17SAhmet Inan return -ENOMEM; 3357e577a17SAhmet Inan 3367e577a17SAhmet Inan data->input = input; 337d862a306SSebastian Reichel input_set_drvdata(input, data); 3387e577a17SAhmet Inan 3393bdd21c6SSebastian Reichel input->name = data->info->name; 3407e577a17SAhmet Inan input->id.bustype = BUS_I2C; 3417e577a17SAhmet Inan 3423bdd21c6SSebastian Reichel max_xy = data->info->max_xy; 3433bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 3443bdd21c6SSebastian Reichel input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 3453bdd21c6SSebastian Reichel 3467e577a17SAhmet Inan touchscreen_parse_properties(input, true, &data->prop); 3477e577a17SAhmet Inan 3487e577a17SAhmet Inan error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, 3497e577a17SAhmet Inan INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 3507e577a17SAhmet Inan if (error) 3517e577a17SAhmet Inan return error; 3527e577a17SAhmet Inan 3537e577a17SAhmet Inan error = input_register_device(input); 3547e577a17SAhmet Inan if (error) 3557e577a17SAhmet Inan return error; 3567e577a17SAhmet Inan 3577e577a17SAhmet Inan error = devm_request_threaded_irq(&client->dev, client->irq, 3587e577a17SAhmet Inan NULL, exc3000_interrupt, IRQF_ONESHOT, 3597e577a17SAhmet Inan client->name, data); 3607e577a17SAhmet Inan if (error) 3617e577a17SAhmet Inan return error; 3627e577a17SAhmet Inan 363d862a306SSebastian Reichel /* 364d862a306SSebastian Reichel * I²C does not have built-in recovery, so retry on failure. This 365d862a306SSebastian Reichel * ensures, that the device probe will not fail for temporary issues 366d862a306SSebastian Reichel * on the bus. This is not needed for the sysfs calls (userspace 367d862a306SSebastian Reichel * will receive the error code and can start another query) and 368d862a306SSebastian Reichel * cannot be done for touch events (but that only means loosing one 369d862a306SSebastian Reichel * or two touch events anyways). 370d862a306SSebastian Reichel */ 371d862a306SSebastian Reichel for (retry = 0; retry < 3; retry++) { 372*102feb1dSLucas Stach u8 response[EXC3000_LEN_FRAME]; 373*102feb1dSLucas Stach 374*102feb1dSLucas Stach error = exc3000_vendor_data_request(data, (u8[]){'E'}, 1, 375*102feb1dSLucas Stach response, 1); 376*102feb1dSLucas Stach if (error > 0) { 377*102feb1dSLucas Stach dev_dbg(&client->dev, "TS Model: %s", &response[1]); 378*102feb1dSLucas Stach error = 0; 379d862a306SSebastian Reichel break; 380*102feb1dSLucas Stach } 381d862a306SSebastian Reichel dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n", 382d862a306SSebastian Reichel retry + 1, error); 383d862a306SSebastian Reichel } 384d862a306SSebastian Reichel 385d862a306SSebastian Reichel if (error) 386d862a306SSebastian Reichel return error; 387d862a306SSebastian Reichel 388d862a306SSebastian Reichel i2c_set_clientdata(client, data); 389d862a306SSebastian Reichel 390d862a306SSebastian Reichel error = devm_device_add_group(&client->dev, &exc3000_attribute_group); 391d862a306SSebastian Reichel if (error) 392d862a306SSebastian Reichel return error; 393d862a306SSebastian Reichel 3947e577a17SAhmet Inan return 0; 3957e577a17SAhmet Inan } 3967e577a17SAhmet Inan 3977e577a17SAhmet Inan static const struct i2c_device_id exc3000_id[] = { 3983bdd21c6SSebastian Reichel { "exc3000", EETI_EXC3000 }, 3993bdd21c6SSebastian Reichel { "exc80h60", EETI_EXC80H60 }, 4003bdd21c6SSebastian Reichel { "exc80h84", EETI_EXC80H84 }, 4017e577a17SAhmet Inan { } 4027e577a17SAhmet Inan }; 4037e577a17SAhmet Inan MODULE_DEVICE_TABLE(i2c, exc3000_id); 4047e577a17SAhmet Inan 4057e577a17SAhmet Inan #ifdef CONFIG_OF 4067e577a17SAhmet Inan static const struct of_device_id exc3000_of_match[] = { 4073bdd21c6SSebastian Reichel { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] }, 4083bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] }, 4093bdd21c6SSebastian Reichel { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] }, 4107e577a17SAhmet Inan { } 4117e577a17SAhmet Inan }; 4127e577a17SAhmet Inan MODULE_DEVICE_TABLE(of, exc3000_of_match); 4137e577a17SAhmet Inan #endif 4147e577a17SAhmet Inan 4157e577a17SAhmet Inan static struct i2c_driver exc3000_driver = { 4167e577a17SAhmet Inan .driver = { 4177e577a17SAhmet Inan .name = "exc3000", 4187e577a17SAhmet Inan .of_match_table = of_match_ptr(exc3000_of_match), 4197e577a17SAhmet Inan }, 4207e577a17SAhmet Inan .id_table = exc3000_id, 421deae5764SSebastian Reichel .probe_new = exc3000_probe, 4227e577a17SAhmet Inan }; 4237e577a17SAhmet Inan 4247e577a17SAhmet Inan module_i2c_driver(exc3000_driver); 4257e577a17SAhmet Inan 4267e577a17SAhmet Inan MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); 4277e577a17SAhmet Inan MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); 4287e577a17SAhmet Inan MODULE_LICENSE("GPL v2"); 429