18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for ELAN eKTF2127 i2c touchscreen controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * For this driver the layout of the Chipone icn8318 i2c 68c2ecf20Sopenharmony_ci * touchscreencontroller is used. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: 98c2ecf20Sopenharmony_ci * Michel Verlaan <michel.verl@gmail.com> 108c2ecf20Sopenharmony_ci * Siebren Vroegindeweij <siebren.vroegindeweij@hotmail.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Original chipone_icn8318 driver: 138c2ecf20Sopenharmony_ci * Hans de Goede <hdegoede@redhat.com> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/i2c.h> 198c2ecf20Sopenharmony_ci#include <linux/input.h> 208c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 218c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Packet header defines (first byte of data send / received) */ 278c2ecf20Sopenharmony_ci#define EKTF2127_NOISE 0x40 288c2ecf20Sopenharmony_ci#define EKTF2127_RESPONSE 0x52 298c2ecf20Sopenharmony_ci#define EKTF2127_REQUEST 0x53 308c2ecf20Sopenharmony_ci#define EKTF2127_HELLO 0x55 318c2ecf20Sopenharmony_ci#define EKTF2127_REPORT 0x5d 328c2ecf20Sopenharmony_ci#define EKTF2127_CALIB_DONE 0x66 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Register defines (second byte of data send / received) */ 358c2ecf20Sopenharmony_ci#define EKTF2127_ENV_NOISY 0x41 368c2ecf20Sopenharmony_ci#define EKTF2127_HEIGHT 0x60 378c2ecf20Sopenharmony_ci#define EKTF2127_WIDTH 0x63 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 2 bytes header + 5 * 3 bytes coordinates + 3 bytes pressure info + footer */ 408c2ecf20Sopenharmony_ci#define EKTF2127_TOUCH_REPORT_SIZE 21 418c2ecf20Sopenharmony_ci#define EKTF2127_MAX_TOUCHES 5 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct ektf2127_ts { 448c2ecf20Sopenharmony_ci struct i2c_client *client; 458c2ecf20Sopenharmony_ci struct input_dev *input; 468c2ecf20Sopenharmony_ci struct gpio_desc *power_gpios; 478c2ecf20Sopenharmony_ci struct touchscreen_properties prop; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void ektf2127_parse_coordinates(const u8 *buf, unsigned int touch_count, 518c2ecf20Sopenharmony_ci struct input_mt_pos *touches) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci int index = 0; 548c2ecf20Sopenharmony_ci int i; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci for (i = 0; i < touch_count; i++) { 578c2ecf20Sopenharmony_ci index = 2 + i * 3; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci touches[i].x = (buf[index] & 0x0f); 608c2ecf20Sopenharmony_ci touches[i].x <<= 8; 618c2ecf20Sopenharmony_ci touches[i].x |= buf[index + 2]; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci touches[i].y = (buf[index] & 0xf0); 648c2ecf20Sopenharmony_ci touches[i].y <<= 4; 658c2ecf20Sopenharmony_ci touches[i].y |= buf[index + 1]; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct input_mt_pos touches[EKTF2127_MAX_TOUCHES]; 728c2ecf20Sopenharmony_ci int slots[EKTF2127_MAX_TOUCHES]; 738c2ecf20Sopenharmony_ci unsigned int touch_count, i; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci touch_count = buf[1] & 0x07; 768c2ecf20Sopenharmony_ci if (touch_count > EKTF2127_MAX_TOUCHES) { 778c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 788c2ecf20Sopenharmony_ci "Too many touches %d > %d\n", 798c2ecf20Sopenharmony_ci touch_count, EKTF2127_MAX_TOUCHES); 808c2ecf20Sopenharmony_ci touch_count = EKTF2127_MAX_TOUCHES; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ektf2127_parse_coordinates(buf, touch_count, touches); 848c2ecf20Sopenharmony_ci input_mt_assign_slots(ts->input, slots, touches, 858c2ecf20Sopenharmony_ci touch_count, 0); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < touch_count; i++) { 888c2ecf20Sopenharmony_ci input_mt_slot(ts->input, slots[i]); 898c2ecf20Sopenharmony_ci input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); 908c2ecf20Sopenharmony_ci touchscreen_report_pos(ts->input, &ts->prop, 918c2ecf20Sopenharmony_ci touches[i].x, touches[i].y, true); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci input_mt_sync_frame(ts->input); 958c2ecf20Sopenharmony_ci input_sync(ts->input); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic irqreturn_t ektf2127_irq(int irq, void *dev_id) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ektf2127_ts *ts = dev_id; 1018c2ecf20Sopenharmony_ci struct device *dev = &ts->client->dev; 1028c2ecf20Sopenharmony_ci char buf[EKTF2127_TOUCH_REPORT_SIZE]; 1038c2ecf20Sopenharmony_ci int ret; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci ret = i2c_master_recv(ts->client, buf, EKTF2127_TOUCH_REPORT_SIZE); 1068c2ecf20Sopenharmony_ci if (ret != EKTF2127_TOUCH_REPORT_SIZE) { 1078c2ecf20Sopenharmony_ci dev_err(dev, "Error reading touch data: %d\n", ret); 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci switch (buf[0]) { 1128c2ecf20Sopenharmony_ci case EKTF2127_REPORT: 1138c2ecf20Sopenharmony_ci ektf2127_report_event(ts, buf); 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci case EKTF2127_NOISE: 1178c2ecf20Sopenharmony_ci if (buf[1] == EKTF2127_ENV_NOISY) 1188c2ecf20Sopenharmony_ci dev_dbg(dev, "Environment is electrically noisy\n"); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci case EKTF2127_HELLO: 1228c2ecf20Sopenharmony_ci case EKTF2127_CALIB_DONE: 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci dev_err(dev, "Unexpected packet header byte %#02x\n", buf[0]); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciout: 1318c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int ektf2127_start(struct input_dev *dev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct ektf2127_ts *ts = input_get_drvdata(dev); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci enable_irq(ts->client->irq); 1398c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->power_gpios, 1); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void ektf2127_stop(struct input_dev *dev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct ektf2127_ts *ts = input_get_drvdata(dev); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci disable_irq(ts->client->irq); 1498c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(ts->power_gpios, 0); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int __maybe_unused ektf2127_suspend(struct device *dev) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci mutex_lock(&ts->input->mutex); 1578c2ecf20Sopenharmony_ci if (ts->input->users) 1588c2ecf20Sopenharmony_ci ektf2127_stop(ts->input); 1598c2ecf20Sopenharmony_ci mutex_unlock(&ts->input->mutex); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int __maybe_unused ektf2127_resume(struct device *dev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mutex_lock(&ts->input->mutex); 1698c2ecf20Sopenharmony_ci if (ts->input->users) 1708c2ecf20Sopenharmony_ci ektf2127_start(ts->input); 1718c2ecf20Sopenharmony_ci mutex_unlock(&ts->input->mutex); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend, 1778c2ecf20Sopenharmony_ci ektf2127_resume); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int ektf2127_query_dimension(struct i2c_client *client, bool width) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 1828c2ecf20Sopenharmony_ci const char *what = width ? "width" : "height"; 1838c2ecf20Sopenharmony_ci u8 what_code = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; 1848c2ecf20Sopenharmony_ci u8 buf[4]; 1858c2ecf20Sopenharmony_ci int ret; 1868c2ecf20Sopenharmony_ci int error; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Request dimension */ 1898c2ecf20Sopenharmony_ci buf[0] = EKTF2127_REQUEST; 1908c2ecf20Sopenharmony_ci buf[1] = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; 1918c2ecf20Sopenharmony_ci buf[2] = 0x00; 1928c2ecf20Sopenharmony_ci buf[3] = 0x00; 1938c2ecf20Sopenharmony_ci ret = i2c_master_send(client, buf, sizeof(buf)); 1948c2ecf20Sopenharmony_ci if (ret != sizeof(buf)) { 1958c2ecf20Sopenharmony_ci error = ret < 0 ? ret : -EIO; 1968c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request %s: %d\n", what, error); 1978c2ecf20Sopenharmony_ci return error; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci msleep(20); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Read response */ 2038c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, buf, sizeof(buf)); 2048c2ecf20Sopenharmony_ci if (ret != sizeof(buf)) { 2058c2ecf20Sopenharmony_ci error = ret < 0 ? ret : -EIO; 2068c2ecf20Sopenharmony_ci dev_err(dev, "Failed to receive %s data: %d\n", what, error); 2078c2ecf20Sopenharmony_ci return error; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (buf[0] != EKTF2127_RESPONSE || buf[1] != what_code) { 2118c2ecf20Sopenharmony_ci dev_err(dev, "Unexpected %s data: %#02x %#02x\n", 2128c2ecf20Sopenharmony_ci what, buf[0], buf[1]); 2138c2ecf20Sopenharmony_ci return -EIO; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return (((buf[3] & 0xf0) << 4) | buf[2]) - 1; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int ektf2127_probe(struct i2c_client *client, 2208c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 2238c2ecf20Sopenharmony_ci struct ektf2127_ts *ts; 2248c2ecf20Sopenharmony_ci struct input_dev *input; 2258c2ecf20Sopenharmony_ci u8 buf[4]; 2268c2ecf20Sopenharmony_ci int max_x, max_y; 2278c2ecf20Sopenharmony_ci int error; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!client->irq) { 2308c2ecf20Sopenharmony_ci dev_err(dev, "Error no irq specified\n"); 2318c2ecf20Sopenharmony_ci return -EINVAL; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); 2358c2ecf20Sopenharmony_ci if (!ts) 2368c2ecf20Sopenharmony_ci return -ENOMEM; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* This requests the gpio *and* turns on the touchscreen controller */ 2398c2ecf20Sopenharmony_ci ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); 2408c2ecf20Sopenharmony_ci if (IS_ERR(ts->power_gpios)) { 2418c2ecf20Sopenharmony_ci error = PTR_ERR(ts->power_gpios); 2428c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 2438c2ecf20Sopenharmony_ci dev_err(dev, "Error getting power gpio: %d\n", error); 2448c2ecf20Sopenharmony_ci return error; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci input = devm_input_allocate_device(dev); 2488c2ecf20Sopenharmony_ci if (!input) 2498c2ecf20Sopenharmony_ci return -ENOMEM; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci input->name = client->name; 2528c2ecf20Sopenharmony_ci input->id.bustype = BUS_I2C; 2538c2ecf20Sopenharmony_ci input->open = ektf2127_start; 2548c2ecf20Sopenharmony_ci input->close = ektf2127_stop; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ts->client = client; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Read hello (ignore result, depends on initial power state) */ 2598c2ecf20Sopenharmony_ci msleep(20); 2608c2ecf20Sopenharmony_ci i2c_master_recv(ts->client, buf, sizeof(buf)); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Read resolution from chip */ 2638c2ecf20Sopenharmony_ci max_x = ektf2127_query_dimension(client, true); 2648c2ecf20Sopenharmony_ci if (max_x < 0) 2658c2ecf20Sopenharmony_ci return max_x; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci max_y = ektf2127_query_dimension(client, false); 2688c2ecf20Sopenharmony_ci if (max_y < 0) 2698c2ecf20Sopenharmony_ci return max_y; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); 2728c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); 2738c2ecf20Sopenharmony_ci touchscreen_parse_properties(input, true, &ts->prop); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci error = input_mt_init_slots(input, EKTF2127_MAX_TOUCHES, 2768c2ecf20Sopenharmony_ci INPUT_MT_DIRECT | 2778c2ecf20Sopenharmony_ci INPUT_MT_DROP_UNUSED | 2788c2ecf20Sopenharmony_ci INPUT_MT_TRACK); 2798c2ecf20Sopenharmony_ci if (error) 2808c2ecf20Sopenharmony_ci return error; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ts->input = input; 2838c2ecf20Sopenharmony_ci input_set_drvdata(input, ts); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(dev, client->irq, 2868c2ecf20Sopenharmony_ci NULL, ektf2127_irq, 2878c2ecf20Sopenharmony_ci IRQF_ONESHOT, client->name, ts); 2888c2ecf20Sopenharmony_ci if (error) { 2898c2ecf20Sopenharmony_ci dev_err(dev, "Error requesting irq: %d\n", error); 2908c2ecf20Sopenharmony_ci return error; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Stop device till opened */ 2948c2ecf20Sopenharmony_ci ektf2127_stop(ts->input); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci error = input_register_device(input); 2978c2ecf20Sopenharmony_ci if (error) 2988c2ecf20Sopenharmony_ci return error; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ts); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3068c2ecf20Sopenharmony_cistatic const struct of_device_id ektf2127_of_match[] = { 3078c2ecf20Sopenharmony_ci { .compatible = "elan,ektf2127" }, 3088c2ecf20Sopenharmony_ci {} 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ektf2127_of_match); 3118c2ecf20Sopenharmony_ci#endif 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic const struct i2c_device_id ektf2127_i2c_id[] = { 3148c2ecf20Sopenharmony_ci { "ektf2127", 0 }, 3158c2ecf20Sopenharmony_ci {} 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic struct i2c_driver ektf2127_driver = { 3208c2ecf20Sopenharmony_ci .driver = { 3218c2ecf20Sopenharmony_ci .name = "elan_ektf2127", 3228c2ecf20Sopenharmony_ci .pm = &ektf2127_pm_ops, 3238c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ektf2127_of_match), 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci .probe = ektf2127_probe, 3268c2ecf20Sopenharmony_ci .id_table = ektf2127_i2c_id, 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_cimodule_i2c_driver(ektf2127_driver); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); 3318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); 3328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 333