162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Touch Screen driver for EETI's I2C connected touch screen panels 462306a36Sopenharmony_ci * Copyright (c) 2009,2018 Daniel Mack <daniel@zonque.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * See EETI's software guide for the protocol specification: 762306a36Sopenharmony_ci * http://home.eeti.com.tw/documentation.html 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on migor_ts.c 1062306a36Sopenharmony_ci * Copyright (c) 2008 Magnus Damm 1162306a36Sopenharmony_ci * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com> 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/input.h> 1762306a36Sopenharmony_ci#include <linux/input/touchscreen.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <linux/i2c.h> 2062306a36Sopenharmony_ci#include <linux/timer.h> 2162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <asm/unaligned.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct eeti_ts { 2762306a36Sopenharmony_ci struct i2c_client *client; 2862306a36Sopenharmony_ci struct input_dev *input; 2962306a36Sopenharmony_ci struct gpio_desc *attn_gpio; 3062306a36Sopenharmony_ci struct touchscreen_properties props; 3162306a36Sopenharmony_ci struct mutex mutex; 3262306a36Sopenharmony_ci bool running; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define EETI_TS_BITDEPTH (11) 3662306a36Sopenharmony_ci#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define REPORT_BIT_PRESSED BIT(0) 3962306a36Sopenharmony_ci#define REPORT_BIT_AD0 BIT(1) 4062306a36Sopenharmony_ci#define REPORT_BIT_AD1 BIT(2) 4162306a36Sopenharmony_ci#define REPORT_BIT_HAS_PRESSURE BIT(6) 4262306a36Sopenharmony_ci#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci unsigned int res; 4762306a36Sopenharmony_ci u16 x, y; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci x = get_unaligned_be16(&buf[1]); 5262306a36Sopenharmony_ci y = get_unaligned_be16(&buf[3]); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* fix the range to 11 bits */ 5562306a36Sopenharmony_ci x >>= res - EETI_TS_BITDEPTH; 5662306a36Sopenharmony_ci y >>= res - EETI_TS_BITDEPTH; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (buf[0] & REPORT_BIT_HAS_PRESSURE) 5962306a36Sopenharmony_ci input_report_abs(eeti->input, ABS_PRESSURE, buf[5]); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci touchscreen_report_pos(eeti->input, &eeti->props, x, y, false); 6262306a36Sopenharmony_ci input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED); 6362306a36Sopenharmony_ci input_sync(eeti->input); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int eeti_ts_read(struct eeti_ts *eeti) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int len, error; 6962306a36Sopenharmony_ci char buf[6]; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci len = i2c_master_recv(eeti->client, buf, sizeof(buf)); 7262306a36Sopenharmony_ci if (len != sizeof(buf)) { 7362306a36Sopenharmony_ci error = len < 0 ? len : -EIO; 7462306a36Sopenharmony_ci dev_err(&eeti->client->dev, 7562306a36Sopenharmony_ci "failed to read touchscreen data: %d\n", 7662306a36Sopenharmony_ci error); 7762306a36Sopenharmony_ci return error; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Motion packet */ 8162306a36Sopenharmony_ci if (buf[0] & 0x80) 8262306a36Sopenharmony_ci eeti_ts_report_event(eeti, buf); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic irqreturn_t eeti_ts_isr(int irq, void *dev_id) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct eeti_ts *eeti = dev_id; 9062306a36Sopenharmony_ci int error; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mutex_lock(&eeti->mutex); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci do { 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * If we have attention GPIO, trust it. Otherwise we'll read 9762306a36Sopenharmony_ci * once and exit. We assume that in this case we are using 9862306a36Sopenharmony_ci * level triggered interrupt and it will get raised again 9962306a36Sopenharmony_ci * if/when there is more data. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci if (eeti->attn_gpio && 10262306a36Sopenharmony_ci !gpiod_get_value_cansleep(eeti->attn_gpio)) { 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci error = eeti_ts_read(eeti); 10762306a36Sopenharmony_ci if (error) 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci } while (eeti->running && eeti->attn_gpio); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mutex_unlock(&eeti->mutex); 11362306a36Sopenharmony_ci return IRQ_HANDLED; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void eeti_ts_start(struct eeti_ts *eeti) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci mutex_lock(&eeti->mutex); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci eeti->running = true; 12162306a36Sopenharmony_ci enable_irq(eeti->client->irq); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * Kick the controller in case we are using edge interrupt and 12562306a36Sopenharmony_ci * we missed our edge while interrupt was disabled. We expect 12662306a36Sopenharmony_ci * the attention GPIO to be wired in this case. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) 12962306a36Sopenharmony_ci eeti_ts_read(eeti); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci mutex_unlock(&eeti->mutex); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void eeti_ts_stop(struct eeti_ts *eeti) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Not locking here, just setting a flag and expect that the 13862306a36Sopenharmony_ci * interrupt thread will notice the flag eventually. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci eeti->running = false; 14162306a36Sopenharmony_ci wmb(); 14262306a36Sopenharmony_ci disable_irq(eeti->client->irq); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int eeti_ts_open(struct input_dev *dev) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct eeti_ts *eeti = input_get_drvdata(dev); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci eeti_ts_start(eeti); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void eeti_ts_close(struct input_dev *dev) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct eeti_ts *eeti = input_get_drvdata(dev); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci eeti_ts_stop(eeti); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int eeti_ts_probe(struct i2c_client *client) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct device *dev = &client->dev; 16462306a36Sopenharmony_ci struct eeti_ts *eeti; 16562306a36Sopenharmony_ci struct input_dev *input; 16662306a36Sopenharmony_ci int error; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * In contrast to what's described in the datasheet, there seems 17062306a36Sopenharmony_ci * to be no way of probing the presence of that device using I2C 17162306a36Sopenharmony_ci * commands. So we need to blindly believe it is there, and wait 17262306a36Sopenharmony_ci * for interrupts to occur. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci eeti = devm_kzalloc(dev, sizeof(*eeti), GFP_KERNEL); 17662306a36Sopenharmony_ci if (!eeti) { 17762306a36Sopenharmony_ci dev_err(dev, "failed to allocate driver data\n"); 17862306a36Sopenharmony_ci return -ENOMEM; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci mutex_init(&eeti->mutex); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci input = devm_input_allocate_device(dev); 18462306a36Sopenharmony_ci if (!input) { 18562306a36Sopenharmony_ci dev_err(dev, "Failed to allocate input device.\n"); 18662306a36Sopenharmony_ci return -ENOMEM; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci input_set_capability(input, EV_KEY, BTN_TOUCH); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0); 19262306a36Sopenharmony_ci input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0); 19362306a36Sopenharmony_ci input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci touchscreen_parse_properties(input, false, &eeti->props); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci input->name = client->name; 19862306a36Sopenharmony_ci input->id.bustype = BUS_I2C; 19962306a36Sopenharmony_ci input->open = eeti_ts_open; 20062306a36Sopenharmony_ci input->close = eeti_ts_close; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci eeti->client = client; 20362306a36Sopenharmony_ci eeti->input = input; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci eeti->attn_gpio = devm_gpiod_get_optional(dev, "attn", GPIOD_IN); 20662306a36Sopenharmony_ci if (IS_ERR(eeti->attn_gpio)) 20762306a36Sopenharmony_ci return PTR_ERR(eeti->attn_gpio); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci i2c_set_clientdata(client, eeti); 21062306a36Sopenharmony_ci input_set_drvdata(input, eeti); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci error = devm_request_threaded_irq(dev, client->irq, 21362306a36Sopenharmony_ci NULL, eeti_ts_isr, 21462306a36Sopenharmony_ci IRQF_ONESHOT, 21562306a36Sopenharmony_ci client->name, eeti); 21662306a36Sopenharmony_ci if (error) { 21762306a36Sopenharmony_ci dev_err(dev, "Unable to request touchscreen IRQ: %d\n", 21862306a36Sopenharmony_ci error); 21962306a36Sopenharmony_ci return error; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * Disable the device for now. It will be enabled once the 22462306a36Sopenharmony_ci * input device is opened. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci eeti_ts_stop(eeti); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci error = input_register_device(input); 22962306a36Sopenharmony_ci if (error) 23062306a36Sopenharmony_ci return error; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int eeti_ts_suspend(struct device *dev) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 23862306a36Sopenharmony_ci struct eeti_ts *eeti = i2c_get_clientdata(client); 23962306a36Sopenharmony_ci struct input_dev *input_dev = eeti->input; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci mutex_lock(&input_dev->mutex); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (input_device_enabled(input_dev)) 24462306a36Sopenharmony_ci eeti_ts_stop(eeti); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci mutex_unlock(&input_dev->mutex); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (device_may_wakeup(&client->dev)) 24962306a36Sopenharmony_ci enable_irq_wake(client->irq); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int eeti_ts_resume(struct device *dev) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 25762306a36Sopenharmony_ci struct eeti_ts *eeti = i2c_get_clientdata(client); 25862306a36Sopenharmony_ci struct input_dev *input_dev = eeti->input; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (device_may_wakeup(&client->dev)) 26162306a36Sopenharmony_ci disable_irq_wake(client->irq); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci mutex_lock(&input_dev->mutex); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (input_device_enabled(input_dev)) 26662306a36Sopenharmony_ci eeti_ts_start(eeti); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci mutex_unlock(&input_dev->mutex); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic const struct i2c_device_id eeti_ts_id[] = { 27662306a36Sopenharmony_ci { "eeti_ts", 0 }, 27762306a36Sopenharmony_ci { } 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, eeti_ts_id); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#ifdef CONFIG_OF 28262306a36Sopenharmony_cistatic const struct of_device_id of_eeti_ts_match[] = { 28362306a36Sopenharmony_ci { .compatible = "eeti,exc3000-i2c", }, 28462306a36Sopenharmony_ci { } 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci#endif 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic struct i2c_driver eeti_ts_driver = { 28962306a36Sopenharmony_ci .driver = { 29062306a36Sopenharmony_ci .name = "eeti_ts", 29162306a36Sopenharmony_ci .pm = pm_sleep_ptr(&eeti_ts_pm), 29262306a36Sopenharmony_ci .of_match_table = of_match_ptr(of_eeti_ts_match), 29362306a36Sopenharmony_ci }, 29462306a36Sopenharmony_ci .probe = eeti_ts_probe, 29562306a36Sopenharmony_ci .id_table = eeti_ts_id, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cimodule_i2c_driver(eeti_ts_driver); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciMODULE_DESCRIPTION("EETI Touchscreen driver"); 30162306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@zonque.org>"); 30262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 303