1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29ca5bf50SSiebren Vroegindeweij /* 39ca5bf50SSiebren Vroegindeweij * Driver for ELAN eKTF2127 i2c touchscreen controller 49ca5bf50SSiebren Vroegindeweij * 59ca5bf50SSiebren Vroegindeweij * For this driver the layout of the Chipone icn8318 i2c 69ca5bf50SSiebren Vroegindeweij * touchscreencontroller is used. 79ca5bf50SSiebren Vroegindeweij * 89ca5bf50SSiebren Vroegindeweij * Author: 99ca5bf50SSiebren Vroegindeweij * Michel Verlaan <michel.verl@gmail.com> 109ca5bf50SSiebren Vroegindeweij * Siebren Vroegindeweij <siebren.vroegindeweij@hotmail.com> 119ca5bf50SSiebren Vroegindeweij * 129ca5bf50SSiebren Vroegindeweij * Original chipone_icn8318 driver: 139ca5bf50SSiebren Vroegindeweij * Hans de Goede <hdegoede@redhat.com> 149ca5bf50SSiebren Vroegindeweij */ 159ca5bf50SSiebren Vroegindeweij 169ca5bf50SSiebren Vroegindeweij #include <linux/gpio/consumer.h> 179ca5bf50SSiebren Vroegindeweij #include <linux/interrupt.h> 189ca5bf50SSiebren Vroegindeweij #include <linux/i2c.h> 199ca5bf50SSiebren Vroegindeweij #include <linux/input.h> 209ca5bf50SSiebren Vroegindeweij #include <linux/input/mt.h> 219ca5bf50SSiebren Vroegindeweij #include <linux/input/touchscreen.h> 229ca5bf50SSiebren Vroegindeweij #include <linux/module.h> 239ca5bf50SSiebren Vroegindeweij #include <linux/of.h> 249ca5bf50SSiebren Vroegindeweij #include <linux/delay.h> 259ca5bf50SSiebren Vroegindeweij 269ca5bf50SSiebren Vroegindeweij /* Packet header defines (first byte of data send / received) */ 279ca5bf50SSiebren Vroegindeweij #define EKTF2127_NOISE 0x40 289ca5bf50SSiebren Vroegindeweij #define EKTF2127_RESPONSE 0x52 299ca5bf50SSiebren Vroegindeweij #define EKTF2127_REQUEST 0x53 309ca5bf50SSiebren Vroegindeweij #define EKTF2127_HELLO 0x55 319ca5bf50SSiebren Vroegindeweij #define EKTF2127_REPORT 0x5d 329ca5bf50SSiebren Vroegindeweij #define EKTF2127_CALIB_DONE 0x66 339ca5bf50SSiebren Vroegindeweij 349ca5bf50SSiebren Vroegindeweij /* Register defines (second byte of data send / received) */ 359ca5bf50SSiebren Vroegindeweij #define EKTF2127_ENV_NOISY 0x41 369ca5bf50SSiebren Vroegindeweij #define EKTF2127_HEIGHT 0x60 379ca5bf50SSiebren Vroegindeweij #define EKTF2127_WIDTH 0x63 389ca5bf50SSiebren Vroegindeweij 399ca5bf50SSiebren Vroegindeweij /* 2 bytes header + 5 * 3 bytes coordinates + 3 bytes pressure info + footer */ 409ca5bf50SSiebren Vroegindeweij #define EKTF2127_TOUCH_REPORT_SIZE 21 419ca5bf50SSiebren Vroegindeweij #define EKTF2127_MAX_TOUCHES 5 429ca5bf50SSiebren Vroegindeweij 439ca5bf50SSiebren Vroegindeweij struct ektf2127_ts { 449ca5bf50SSiebren Vroegindeweij struct i2c_client *client; 459ca5bf50SSiebren Vroegindeweij struct input_dev *input; 469ca5bf50SSiebren Vroegindeweij struct gpio_desc *power_gpios; 479ca5bf50SSiebren Vroegindeweij struct touchscreen_properties prop; 489ca5bf50SSiebren Vroegindeweij }; 499ca5bf50SSiebren Vroegindeweij 509ca5bf50SSiebren Vroegindeweij static void ektf2127_parse_coordinates(const u8 *buf, unsigned int touch_count, 519ca5bf50SSiebren Vroegindeweij struct input_mt_pos *touches) 529ca5bf50SSiebren Vroegindeweij { 539ca5bf50SSiebren Vroegindeweij int index = 0; 549ca5bf50SSiebren Vroegindeweij int i; 559ca5bf50SSiebren Vroegindeweij 569ca5bf50SSiebren Vroegindeweij for (i = 0; i < touch_count; i++) { 579ca5bf50SSiebren Vroegindeweij index = 2 + i * 3; 589ca5bf50SSiebren Vroegindeweij 599ca5bf50SSiebren Vroegindeweij touches[i].x = (buf[index] & 0x0f); 609ca5bf50SSiebren Vroegindeweij touches[i].x <<= 8; 619ca5bf50SSiebren Vroegindeweij touches[i].x |= buf[index + 2]; 629ca5bf50SSiebren Vroegindeweij 639ca5bf50SSiebren Vroegindeweij touches[i].y = (buf[index] & 0xf0); 649ca5bf50SSiebren Vroegindeweij touches[i].y <<= 4; 659ca5bf50SSiebren Vroegindeweij touches[i].y |= buf[index + 1]; 669ca5bf50SSiebren Vroegindeweij } 679ca5bf50SSiebren Vroegindeweij } 689ca5bf50SSiebren Vroegindeweij 699ca5bf50SSiebren Vroegindeweij static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) 709ca5bf50SSiebren Vroegindeweij { 719ca5bf50SSiebren Vroegindeweij struct input_mt_pos touches[EKTF2127_MAX_TOUCHES]; 729ca5bf50SSiebren Vroegindeweij int slots[EKTF2127_MAX_TOUCHES]; 739ca5bf50SSiebren Vroegindeweij unsigned int touch_count, i; 749ca5bf50SSiebren Vroegindeweij 759ca5bf50SSiebren Vroegindeweij touch_count = buf[1] & 0x07; 769ca5bf50SSiebren Vroegindeweij if (touch_count > EKTF2127_MAX_TOUCHES) { 779ca5bf50SSiebren Vroegindeweij dev_err(&ts->client->dev, 789ca5bf50SSiebren Vroegindeweij "Too many touches %d > %d\n", 799ca5bf50SSiebren Vroegindeweij touch_count, EKTF2127_MAX_TOUCHES); 809ca5bf50SSiebren Vroegindeweij touch_count = EKTF2127_MAX_TOUCHES; 819ca5bf50SSiebren Vroegindeweij } 829ca5bf50SSiebren Vroegindeweij 839ca5bf50SSiebren Vroegindeweij ektf2127_parse_coordinates(buf, touch_count, touches); 849ca5bf50SSiebren Vroegindeweij input_mt_assign_slots(ts->input, slots, touches, 859ca5bf50SSiebren Vroegindeweij touch_count, 0); 869ca5bf50SSiebren Vroegindeweij 879ca5bf50SSiebren Vroegindeweij for (i = 0; i < touch_count; i++) { 889ca5bf50SSiebren Vroegindeweij input_mt_slot(ts->input, slots[i]); 899ca5bf50SSiebren Vroegindeweij input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); 909ca5bf50SSiebren Vroegindeweij touchscreen_report_pos(ts->input, &ts->prop, 919ca5bf50SSiebren Vroegindeweij touches[i].x, touches[i].y, true); 929ca5bf50SSiebren Vroegindeweij } 939ca5bf50SSiebren Vroegindeweij 949ca5bf50SSiebren Vroegindeweij input_mt_sync_frame(ts->input); 959ca5bf50SSiebren Vroegindeweij input_sync(ts->input); 969ca5bf50SSiebren Vroegindeweij } 979ca5bf50SSiebren Vroegindeweij 989ca5bf50SSiebren Vroegindeweij static irqreturn_t ektf2127_irq(int irq, void *dev_id) 999ca5bf50SSiebren Vroegindeweij { 1009ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts = dev_id; 1019ca5bf50SSiebren Vroegindeweij struct device *dev = &ts->client->dev; 1029ca5bf50SSiebren Vroegindeweij char buf[EKTF2127_TOUCH_REPORT_SIZE]; 1039ca5bf50SSiebren Vroegindeweij int ret; 1049ca5bf50SSiebren Vroegindeweij 1059ca5bf50SSiebren Vroegindeweij ret = i2c_master_recv(ts->client, buf, EKTF2127_TOUCH_REPORT_SIZE); 1069ca5bf50SSiebren Vroegindeweij if (ret != EKTF2127_TOUCH_REPORT_SIZE) { 1079ca5bf50SSiebren Vroegindeweij dev_err(dev, "Error reading touch data: %d\n", ret); 1089ca5bf50SSiebren Vroegindeweij goto out; 1099ca5bf50SSiebren Vroegindeweij } 1109ca5bf50SSiebren Vroegindeweij 1119ca5bf50SSiebren Vroegindeweij switch (buf[0]) { 1129ca5bf50SSiebren Vroegindeweij case EKTF2127_REPORT: 1139ca5bf50SSiebren Vroegindeweij ektf2127_report_event(ts, buf); 1149ca5bf50SSiebren Vroegindeweij break; 1159ca5bf50SSiebren Vroegindeweij 1169ca5bf50SSiebren Vroegindeweij case EKTF2127_NOISE: 1179ca5bf50SSiebren Vroegindeweij if (buf[1] == EKTF2127_ENV_NOISY) 1189ca5bf50SSiebren Vroegindeweij dev_dbg(dev, "Environment is electrically noisy\n"); 1199ca5bf50SSiebren Vroegindeweij break; 1209ca5bf50SSiebren Vroegindeweij 1219ca5bf50SSiebren Vroegindeweij case EKTF2127_HELLO: 1229ca5bf50SSiebren Vroegindeweij case EKTF2127_CALIB_DONE: 1239ca5bf50SSiebren Vroegindeweij break; 1249ca5bf50SSiebren Vroegindeweij 1259ca5bf50SSiebren Vroegindeweij default: 1269ca5bf50SSiebren Vroegindeweij dev_err(dev, "Unexpected packet header byte %#02x\n", buf[0]); 1279ca5bf50SSiebren Vroegindeweij break; 1289ca5bf50SSiebren Vroegindeweij } 1299ca5bf50SSiebren Vroegindeweij 1309ca5bf50SSiebren Vroegindeweij out: 1319ca5bf50SSiebren Vroegindeweij return IRQ_HANDLED; 1329ca5bf50SSiebren Vroegindeweij } 1339ca5bf50SSiebren Vroegindeweij 1349ca5bf50SSiebren Vroegindeweij static int ektf2127_start(struct input_dev *dev) 1359ca5bf50SSiebren Vroegindeweij { 1369ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts = input_get_drvdata(dev); 1379ca5bf50SSiebren Vroegindeweij 1389ca5bf50SSiebren Vroegindeweij enable_irq(ts->client->irq); 1399ca5bf50SSiebren Vroegindeweij gpiod_set_value_cansleep(ts->power_gpios, 1); 1409ca5bf50SSiebren Vroegindeweij 1419ca5bf50SSiebren Vroegindeweij return 0; 1429ca5bf50SSiebren Vroegindeweij } 1439ca5bf50SSiebren Vroegindeweij 1449ca5bf50SSiebren Vroegindeweij static void ektf2127_stop(struct input_dev *dev) 1459ca5bf50SSiebren Vroegindeweij { 1469ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts = input_get_drvdata(dev); 1479ca5bf50SSiebren Vroegindeweij 1489ca5bf50SSiebren Vroegindeweij disable_irq(ts->client->irq); 1499ca5bf50SSiebren Vroegindeweij gpiod_set_value_cansleep(ts->power_gpios, 0); 1509ca5bf50SSiebren Vroegindeweij } 1519ca5bf50SSiebren Vroegindeweij 152979987deSArnd Bergmann static int __maybe_unused ektf2127_suspend(struct device *dev) 1539ca5bf50SSiebren Vroegindeweij { 1549ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); 1559ca5bf50SSiebren Vroegindeweij 1569ca5bf50SSiebren Vroegindeweij mutex_lock(&ts->input->mutex); 1579ca5bf50SSiebren Vroegindeweij if (ts->input->users) 1589ca5bf50SSiebren Vroegindeweij ektf2127_stop(ts->input); 1599ca5bf50SSiebren Vroegindeweij mutex_unlock(&ts->input->mutex); 1609ca5bf50SSiebren Vroegindeweij 1619ca5bf50SSiebren Vroegindeweij return 0; 1629ca5bf50SSiebren Vroegindeweij } 1639ca5bf50SSiebren Vroegindeweij 164979987deSArnd Bergmann static int __maybe_unused ektf2127_resume(struct device *dev) 1659ca5bf50SSiebren Vroegindeweij { 1669ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); 1679ca5bf50SSiebren Vroegindeweij 1689ca5bf50SSiebren Vroegindeweij mutex_lock(&ts->input->mutex); 1699ca5bf50SSiebren Vroegindeweij if (ts->input->users) 1709ca5bf50SSiebren Vroegindeweij ektf2127_start(ts->input); 1719ca5bf50SSiebren Vroegindeweij mutex_unlock(&ts->input->mutex); 1729ca5bf50SSiebren Vroegindeweij 1739ca5bf50SSiebren Vroegindeweij return 0; 1749ca5bf50SSiebren Vroegindeweij } 1759ca5bf50SSiebren Vroegindeweij 1769ca5bf50SSiebren Vroegindeweij static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend, 1779ca5bf50SSiebren Vroegindeweij ektf2127_resume); 1789ca5bf50SSiebren Vroegindeweij 1799ca5bf50SSiebren Vroegindeweij static int ektf2127_query_dimension(struct i2c_client *client, bool width) 1809ca5bf50SSiebren Vroegindeweij { 1819ca5bf50SSiebren Vroegindeweij struct device *dev = &client->dev; 1829ca5bf50SSiebren Vroegindeweij const char *what = width ? "width" : "height"; 1839ca5bf50SSiebren Vroegindeweij u8 what_code = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; 1849ca5bf50SSiebren Vroegindeweij u8 buf[4]; 1859ca5bf50SSiebren Vroegindeweij int ret; 1869ca5bf50SSiebren Vroegindeweij int error; 1879ca5bf50SSiebren Vroegindeweij 1889ca5bf50SSiebren Vroegindeweij /* Request dimension */ 1899ca5bf50SSiebren Vroegindeweij buf[0] = EKTF2127_REQUEST; 1909ca5bf50SSiebren Vroegindeweij buf[1] = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; 1919ca5bf50SSiebren Vroegindeweij buf[2] = 0x00; 1929ca5bf50SSiebren Vroegindeweij buf[3] = 0x00; 1939ca5bf50SSiebren Vroegindeweij ret = i2c_master_send(client, buf, sizeof(buf)); 1949ca5bf50SSiebren Vroegindeweij if (ret != sizeof(buf)) { 1959ca5bf50SSiebren Vroegindeweij error = ret < 0 ? ret : -EIO; 1969ca5bf50SSiebren Vroegindeweij dev_err(dev, "Failed to request %s: %d\n", what, error); 1979ca5bf50SSiebren Vroegindeweij return error; 1989ca5bf50SSiebren Vroegindeweij } 1999ca5bf50SSiebren Vroegindeweij 2009ca5bf50SSiebren Vroegindeweij msleep(20); 2019ca5bf50SSiebren Vroegindeweij 2029ca5bf50SSiebren Vroegindeweij /* Read response */ 2039ca5bf50SSiebren Vroegindeweij ret = i2c_master_recv(client, buf, sizeof(buf)); 2049ca5bf50SSiebren Vroegindeweij if (ret != sizeof(buf)) { 2059ca5bf50SSiebren Vroegindeweij error = ret < 0 ? ret : -EIO; 2069ca5bf50SSiebren Vroegindeweij dev_err(dev, "Failed to receive %s data: %d\n", what, error); 2079ca5bf50SSiebren Vroegindeweij return error; 2089ca5bf50SSiebren Vroegindeweij } 2099ca5bf50SSiebren Vroegindeweij 2109ca5bf50SSiebren Vroegindeweij if (buf[0] != EKTF2127_RESPONSE || buf[1] != what_code) { 2119ca5bf50SSiebren Vroegindeweij dev_err(dev, "Unexpected %s data: %#02x %#02x\n", 2129ca5bf50SSiebren Vroegindeweij what, buf[0], buf[1]); 2139ca5bf50SSiebren Vroegindeweij return -EIO; 2149ca5bf50SSiebren Vroegindeweij } 2159ca5bf50SSiebren Vroegindeweij 2169ca5bf50SSiebren Vroegindeweij return (((buf[3] & 0xf0) << 4) | buf[2]) - 1; 2179ca5bf50SSiebren Vroegindeweij } 2189ca5bf50SSiebren Vroegindeweij 2199ca5bf50SSiebren Vroegindeweij static int ektf2127_probe(struct i2c_client *client, 2209ca5bf50SSiebren Vroegindeweij const struct i2c_device_id *id) 2219ca5bf50SSiebren Vroegindeweij { 2229ca5bf50SSiebren Vroegindeweij struct device *dev = &client->dev; 2239ca5bf50SSiebren Vroegindeweij struct ektf2127_ts *ts; 2249ca5bf50SSiebren Vroegindeweij struct input_dev *input; 2259ca5bf50SSiebren Vroegindeweij u8 buf[4]; 2269ca5bf50SSiebren Vroegindeweij int max_x, max_y; 2279ca5bf50SSiebren Vroegindeweij int error; 2289ca5bf50SSiebren Vroegindeweij 2299ca5bf50SSiebren Vroegindeweij if (!client->irq) { 2309ca5bf50SSiebren Vroegindeweij dev_err(dev, "Error no irq specified\n"); 2319ca5bf50SSiebren Vroegindeweij return -EINVAL; 2329ca5bf50SSiebren Vroegindeweij } 2339ca5bf50SSiebren Vroegindeweij 2349ca5bf50SSiebren Vroegindeweij ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); 2359ca5bf50SSiebren Vroegindeweij if (!ts) 2369ca5bf50SSiebren Vroegindeweij return -ENOMEM; 2379ca5bf50SSiebren Vroegindeweij 2389ca5bf50SSiebren Vroegindeweij /* This requests the gpio *and* turns on the touchscreen controller */ 2399ca5bf50SSiebren Vroegindeweij ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); 2409ca5bf50SSiebren Vroegindeweij if (IS_ERR(ts->power_gpios)) { 2419ca5bf50SSiebren Vroegindeweij error = PTR_ERR(ts->power_gpios); 2429ca5bf50SSiebren Vroegindeweij if (error != -EPROBE_DEFER) 2439ca5bf50SSiebren Vroegindeweij dev_err(dev, "Error getting power gpio: %d\n", error); 2449ca5bf50SSiebren Vroegindeweij return error; 2459ca5bf50SSiebren Vroegindeweij } 2469ca5bf50SSiebren Vroegindeweij 2479ca5bf50SSiebren Vroegindeweij input = devm_input_allocate_device(dev); 2489ca5bf50SSiebren Vroegindeweij if (!input) 2499ca5bf50SSiebren Vroegindeweij return -ENOMEM; 2509ca5bf50SSiebren Vroegindeweij 2519ca5bf50SSiebren Vroegindeweij input->name = client->name; 2529ca5bf50SSiebren Vroegindeweij input->id.bustype = BUS_I2C; 2539ca5bf50SSiebren Vroegindeweij input->open = ektf2127_start; 2549ca5bf50SSiebren Vroegindeweij input->close = ektf2127_stop; 2559ca5bf50SSiebren Vroegindeweij 2569ca5bf50SSiebren Vroegindeweij ts->client = client; 2579ca5bf50SSiebren Vroegindeweij 2589ca5bf50SSiebren Vroegindeweij /* Read hello (ignore result, depends on initial power state) */ 2599ca5bf50SSiebren Vroegindeweij msleep(20); 2609ca5bf50SSiebren Vroegindeweij i2c_master_recv(ts->client, buf, sizeof(buf)); 2619ca5bf50SSiebren Vroegindeweij 2629ca5bf50SSiebren Vroegindeweij /* Read resolution from chip */ 2639ca5bf50SSiebren Vroegindeweij max_x = ektf2127_query_dimension(client, true); 2649ca5bf50SSiebren Vroegindeweij if (max_x < 0) 2659ca5bf50SSiebren Vroegindeweij return max_x; 2669ca5bf50SSiebren Vroegindeweij 2679ca5bf50SSiebren Vroegindeweij max_y = ektf2127_query_dimension(client, false); 2689ca5bf50SSiebren Vroegindeweij if (max_y < 0) 2699ca5bf50SSiebren Vroegindeweij return max_y; 2709ca5bf50SSiebren Vroegindeweij 2719ca5bf50SSiebren Vroegindeweij input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); 2729ca5bf50SSiebren Vroegindeweij input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); 2739ca5bf50SSiebren Vroegindeweij touchscreen_parse_properties(input, true, &ts->prop); 2749ca5bf50SSiebren Vroegindeweij 2759ca5bf50SSiebren Vroegindeweij error = input_mt_init_slots(input, EKTF2127_MAX_TOUCHES, 2769ca5bf50SSiebren Vroegindeweij INPUT_MT_DIRECT | 2779ca5bf50SSiebren Vroegindeweij INPUT_MT_DROP_UNUSED | 2789ca5bf50SSiebren Vroegindeweij INPUT_MT_TRACK); 2799ca5bf50SSiebren Vroegindeweij if (error) 2809ca5bf50SSiebren Vroegindeweij return error; 2819ca5bf50SSiebren Vroegindeweij 2829ca5bf50SSiebren Vroegindeweij ts->input = input; 2839ca5bf50SSiebren Vroegindeweij input_set_drvdata(input, ts); 2849ca5bf50SSiebren Vroegindeweij 2859ca5bf50SSiebren Vroegindeweij error = devm_request_threaded_irq(dev, client->irq, 2869ca5bf50SSiebren Vroegindeweij NULL, ektf2127_irq, 2879ca5bf50SSiebren Vroegindeweij IRQF_ONESHOT, client->name, ts); 2889ca5bf50SSiebren Vroegindeweij if (error) { 2899ca5bf50SSiebren Vroegindeweij dev_err(dev, "Error requesting irq: %d\n", error); 2909ca5bf50SSiebren Vroegindeweij return error; 2919ca5bf50SSiebren Vroegindeweij } 2929ca5bf50SSiebren Vroegindeweij 2939ca5bf50SSiebren Vroegindeweij /* Stop device till opened */ 2949ca5bf50SSiebren Vroegindeweij ektf2127_stop(ts->input); 2959ca5bf50SSiebren Vroegindeweij 2969ca5bf50SSiebren Vroegindeweij error = input_register_device(input); 2979ca5bf50SSiebren Vroegindeweij if (error) 2989ca5bf50SSiebren Vroegindeweij return error; 2999ca5bf50SSiebren Vroegindeweij 3009ca5bf50SSiebren Vroegindeweij i2c_set_clientdata(client, ts); 3019ca5bf50SSiebren Vroegindeweij 3029ca5bf50SSiebren Vroegindeweij return 0; 3039ca5bf50SSiebren Vroegindeweij } 3049ca5bf50SSiebren Vroegindeweij 3059ca5bf50SSiebren Vroegindeweij #ifdef CONFIG_OF 3069ca5bf50SSiebren Vroegindeweij static const struct of_device_id ektf2127_of_match[] = { 3079ca5bf50SSiebren Vroegindeweij { .compatible = "elan,ektf2127" }, 3089ca5bf50SSiebren Vroegindeweij {} 3099ca5bf50SSiebren Vroegindeweij }; 3109ca5bf50SSiebren Vroegindeweij MODULE_DEVICE_TABLE(of, ektf2127_of_match); 3119ca5bf50SSiebren Vroegindeweij #endif 3129ca5bf50SSiebren Vroegindeweij 3139ca5bf50SSiebren Vroegindeweij static const struct i2c_device_id ektf2127_i2c_id[] = { 3149ca5bf50SSiebren Vroegindeweij { "ektf2127", 0 }, 3159ca5bf50SSiebren Vroegindeweij {} 3169ca5bf50SSiebren Vroegindeweij }; 3179ca5bf50SSiebren Vroegindeweij MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); 3189ca5bf50SSiebren Vroegindeweij 3199ca5bf50SSiebren Vroegindeweij static struct i2c_driver ektf2127_driver = { 3209ca5bf50SSiebren Vroegindeweij .driver = { 3219ca5bf50SSiebren Vroegindeweij .name = "elan_ektf2127", 3229ca5bf50SSiebren Vroegindeweij .pm = &ektf2127_pm_ops, 3239ca5bf50SSiebren Vroegindeweij .of_match_table = of_match_ptr(ektf2127_of_match), 3249ca5bf50SSiebren Vroegindeweij }, 3259ca5bf50SSiebren Vroegindeweij .probe = ektf2127_probe, 3269ca5bf50SSiebren Vroegindeweij .id_table = ektf2127_i2c_id, 3279ca5bf50SSiebren Vroegindeweij }; 3289ca5bf50SSiebren Vroegindeweij module_i2c_driver(ektf2127_driver); 3299ca5bf50SSiebren Vroegindeweij 3309ca5bf50SSiebren Vroegindeweij MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); 3319ca5bf50SSiebren Vroegindeweij MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); 3329ca5bf50SSiebren Vroegindeweij MODULE_LICENSE("GPL"); 333