diff options
Diffstat (limited to 'Input-add-driver-for-the-Goodix-touchpanel.patch')
-rw-r--r-- | Input-add-driver-for-the-Goodix-touchpanel.patch | 479 |
1 files changed, 0 insertions, 479 deletions
diff --git a/Input-add-driver-for-the-Goodix-touchpanel.patch b/Input-add-driver-for-the-Goodix-touchpanel.patch deleted file mode 100644 index 30004ff92..000000000 --- a/Input-add-driver-for-the-Goodix-touchpanel.patch +++ /dev/null @@ -1,479 +0,0 @@ -From: Bastien Nocera <hadess@hadess.net> -Date: Fri, 31 Oct 2014 09:26:16 -0700 -Subject: [PATCH] Input: add driver for the Goodix touchpanel - -Add a driver for the Goodix touchscreen panel found in Onda v975w tablets. -The driver is based off the Android driver gt9xx.c found in some Android -code dumps, but now bears no resemblance to the original driver. - -The driver was tested on the aforementioned tablet. - -Signed-off-by: Bastien Nocera <hadess@hadess.net> -Tested-by: Bastien Nocera <hadess@hadess.net> -Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> -Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> ---- - MAINTAINERS | 6 + - drivers/input/touchscreen/Kconfig | 13 ++ - drivers/input/touchscreen/Makefile | 1 + - drivers/input/touchscreen/goodix.c | 395 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 415 insertions(+) - create mode 100644 drivers/input/touchscreen/goodix.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index c721042e7e45..738708f8b75f 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -4154,6 +4154,12 @@ L: linux-media@vger.kernel.org - S: Maintained - F: drivers/media/usb/go7007/ - -+GOODIX TOUCHSCREEN -+M: Bastien Nocera <hadess@hadess.net> -+L: linux-input@vger.kernel.org -+S: Maintained -+F: drivers/input/touchscreen/goodix.c -+ - GPIO SUBSYSTEM - M: Linus Walleij <linus.walleij@linaro.org> - M: Alexandre Courbot <gnurou@gmail.com> -diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig -index e1d8003d01f8..568a0200fbc2 100644 ---- a/drivers/input/touchscreen/Kconfig -+++ b/drivers/input/touchscreen/Kconfig -@@ -295,6 +295,19 @@ config TOUCHSCREEN_FUJITSU - To compile this driver as a module, choose M here: the - module will be called fujitsu-ts. - -+config TOUCHSCREEN_GOODIX -+ tristate "Goodix I2C touchscreen" -+ depends on I2C && ACPI -+ help -+ Say Y here if you have the Goodix touchscreen (such as one -+ installed in Onda v975w tablets) connected to your -+ system. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called goodix. -+ - config TOUCHSCREEN_ILI210X - tristate "Ilitek ILI210X based touchscreen" - depends on I2C -diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile -index 090e61cc9171..dab4a56ac98e 100644 ---- a/drivers/input/touchscreen/Makefile -+++ b/drivers/input/touchscreen/Makefile -@@ -34,6 +34,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o - obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o - obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o - obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o -+obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o - obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o - obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o - obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o -diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c -new file mode 100644 -index 000000000000..ca196689f025 ---- /dev/null -+++ b/drivers/input/touchscreen/goodix.c -@@ -0,0 +1,395 @@ -+/* -+ * Driver for Goodix Touchscreens -+ * -+ * Copyright (c) 2014 Red Hat Inc. -+ * -+ * This code is based on gt9xx.c authored by andrew@goodix.com: -+ * -+ * 2010 - 2012 Goodix Technology. -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the Free -+ * Software Foundation; version 2 of the License. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/i2c.h> -+#include <linux/input.h> -+#include <linux/input/mt.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/irq.h> -+#include <linux/interrupt.h> -+#include <linux/slab.h> -+#include <asm/unaligned.h> -+ -+struct goodix_ts_data { -+ struct i2c_client *client; -+ struct input_dev *input_dev; -+ int abs_x_max; -+ int abs_y_max; -+ unsigned int max_touch_num; -+ unsigned int int_trigger_type; -+}; -+ -+#define GOODIX_MAX_HEIGHT 4096 -+#define GOODIX_MAX_WIDTH 4096 -+#define GOODIX_INT_TRIGGER 1 -+#define GOODIX_CONTACT_SIZE 8 -+#define GOODIX_MAX_CONTACTS 10 -+ -+#define GOODIX_CONFIG_MAX_LENGTH 240 -+ -+/* Register defines */ -+#define GOODIX_READ_COOR_ADDR 0x814E -+#define GOODIX_REG_CONFIG_DATA 0x8047 -+#define GOODIX_REG_VERSION 0x8140 -+ -+#define RESOLUTION_LOC 1 -+#define TRIGGER_LOC 6 -+ -+static const unsigned long goodix_irq_flags[] = { -+ IRQ_TYPE_EDGE_RISING, -+ IRQ_TYPE_EDGE_FALLING, -+ IRQ_TYPE_LEVEL_LOW, -+ IRQ_TYPE_LEVEL_HIGH, -+}; -+ -+/** -+ * goodix_i2c_read - read data from a register of the i2c slave device. -+ * -+ * @client: i2c device. -+ * @reg: the register to read from. -+ * @buf: raw write data buffer. -+ * @len: length of the buffer to write -+ */ -+static int goodix_i2c_read(struct i2c_client *client, -+ u16 reg, u8 *buf, int len) -+{ -+ struct i2c_msg msgs[2]; -+ u16 wbuf = cpu_to_be16(reg); -+ int ret; -+ -+ msgs[0].flags = 0; -+ msgs[0].addr = client->addr; -+ msgs[0].len = 2; -+ msgs[0].buf = (u8 *) &wbuf; -+ -+ msgs[1].flags = I2C_M_RD; -+ msgs[1].addr = client->addr; -+ msgs[1].len = len; -+ msgs[1].buf = buf; -+ -+ ret = i2c_transfer(client->adapter, msgs, 2); -+ return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); -+} -+ -+static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) -+{ -+ int touch_num; -+ int error; -+ -+ error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data, -+ GOODIX_CONTACT_SIZE + 1); -+ if (error) { -+ dev_err(&ts->client->dev, "I2C transfer error: %d\n", error); -+ return error; -+ } -+ -+ touch_num = data[0] & 0x0f; -+ if (touch_num > GOODIX_MAX_CONTACTS) -+ return -EPROTO; -+ -+ if (touch_num > 1) { -+ data += 1 + GOODIX_CONTACT_SIZE; -+ error = goodix_i2c_read(ts->client, -+ GOODIX_READ_COOR_ADDR + -+ 1 + GOODIX_CONTACT_SIZE, -+ data, -+ GOODIX_CONTACT_SIZE * (touch_num - 1)); -+ if (error) -+ return error; -+ } -+ -+ return touch_num; -+} -+ -+static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data) -+{ -+ int id = coor_data[0] & 0x0F; -+ int input_x = get_unaligned_le16(&coor_data[1]); -+ int input_y = get_unaligned_le16(&coor_data[3]); -+ int input_w = get_unaligned_le16(&coor_data[5]); -+ -+ input_mt_slot(ts->input_dev, id); -+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); -+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); -+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); -+} -+ -+/** -+ * goodix_process_events - Process incoming events -+ * -+ * @ts: our goodix_ts_data pointer -+ * -+ * Called when the IRQ is triggered. Read the current device state, and push -+ * the input events to the user space. -+ */ -+static void goodix_process_events(struct goodix_ts_data *ts) -+{ -+ u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS]; -+ int touch_num; -+ int i; -+ -+ touch_num = goodix_ts_read_input_report(ts, point_data); -+ if (touch_num < 0) -+ return; -+ -+ for (i = 0; i < touch_num; i++) -+ goodix_ts_report_touch(ts, -+ &point_data[1 + GOODIX_CONTACT_SIZE * i]); -+ -+ input_mt_sync_frame(ts->input_dev); -+ input_sync(ts->input_dev); -+} -+ -+/** -+ * goodix_ts_irq_handler - The IRQ handler -+ * -+ * @irq: interrupt number. -+ * @dev_id: private data pointer. -+ */ -+static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) -+{ -+ static const u8 end_cmd[] = { -+ GOODIX_READ_COOR_ADDR >> 8, -+ GOODIX_READ_COOR_ADDR & 0xff, -+ 0 -+ }; -+ struct goodix_ts_data *ts = dev_id; -+ -+ goodix_process_events(ts); -+ -+ if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0) -+ dev_err(&ts->client->dev, "I2C write end_cmd error\n"); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * goodix_read_config - Read the embedded configuration of the panel -+ * -+ * @ts: our goodix_ts_data pointer -+ * -+ * Must be called during probe -+ */ -+static void goodix_read_config(struct goodix_ts_data *ts) -+{ -+ u8 config[GOODIX_CONFIG_MAX_LENGTH]; -+ int error; -+ -+ error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, -+ config, -+ GOODIX_CONFIG_MAX_LENGTH); -+ if (error) { -+ dev_warn(&ts->client->dev, -+ "Error reading config (%d), using defaults\n", -+ error); -+ ts->abs_x_max = GOODIX_MAX_WIDTH; -+ ts->abs_y_max = GOODIX_MAX_HEIGHT; -+ ts->int_trigger_type = GOODIX_INT_TRIGGER; -+ return; -+ } -+ -+ ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]); -+ ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]); -+ ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; -+ if (!ts->abs_x_max || !ts->abs_y_max) { -+ dev_err(&ts->client->dev, -+ "Invalid config, using defaults\n"); -+ ts->abs_x_max = GOODIX_MAX_WIDTH; -+ ts->abs_y_max = GOODIX_MAX_HEIGHT; -+ } -+} -+ -+ -+/** -+ * goodix_read_version - Read goodix touchscreen version -+ * -+ * @client: the i2c client -+ * @version: output buffer containing the version on success -+ */ -+static int goodix_read_version(struct i2c_client *client, u16 *version) -+{ -+ int error; -+ u8 buf[6]; -+ -+ error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf)); -+ if (error) { -+ dev_err(&client->dev, "read version failed: %d\n", error); -+ return error; -+ } -+ -+ if (version) -+ *version = get_unaligned_le16(&buf[4]); -+ -+ dev_info(&client->dev, "IC VERSION: %6ph\n", buf); -+ -+ return 0; -+} -+ -+/** -+ * goodix_i2c_test - I2C test function to check if the device answers. -+ * -+ * @client: the i2c client -+ */ -+static int goodix_i2c_test(struct i2c_client *client) -+{ -+ int retry = 0; -+ int error; -+ u8 test; -+ -+ while (retry++ < 2) { -+ error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA, -+ &test, 1); -+ if (!error) -+ return 0; -+ -+ dev_err(&client->dev, "i2c test failed attempt %d: %d\n", -+ retry, error); -+ msleep(20); -+ } -+ -+ return error; -+} -+ -+/** -+ * goodix_request_input_dev - Allocate, populate and register the input device -+ * -+ * @ts: our goodix_ts_data pointer -+ * -+ * Must be called during probe -+ */ -+static int goodix_request_input_dev(struct goodix_ts_data *ts) -+{ -+ int error; -+ -+ ts->input_dev = devm_input_allocate_device(&ts->client->dev); -+ if (!ts->input_dev) { -+ dev_err(&ts->client->dev, "Failed to allocate input device."); -+ return -ENOMEM; -+ } -+ -+ ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | -+ BIT_MASK(EV_KEY) | -+ BIT_MASK(EV_ABS); -+ -+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, -+ ts->abs_x_max, 0, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, -+ ts->abs_y_max, 0, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); -+ -+ input_mt_init_slots(ts->input_dev, GOODIX_MAX_CONTACTS, -+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); -+ -+ ts->input_dev->name = "Goodix Capacitive TouchScreen"; -+ ts->input_dev->phys = "input/ts"; -+ ts->input_dev->id.bustype = BUS_I2C; -+ ts->input_dev->id.vendor = 0x0416; -+ ts->input_dev->id.product = 0x1001; -+ ts->input_dev->id.version = 10427; -+ -+ error = input_register_device(ts->input_dev); -+ if (error) { -+ dev_err(&ts->client->dev, -+ "Failed to register input device: %d", error); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int goodix_ts_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct goodix_ts_data *ts; -+ unsigned long irq_flags; -+ int error; -+ u16 version_info; -+ -+ dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { -+ dev_err(&client->dev, "I2C check functionality failed.\n"); -+ return -ENXIO; -+ } -+ -+ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); -+ if (!ts) -+ return -ENOMEM; -+ -+ ts->client = client; -+ i2c_set_clientdata(client, ts); -+ -+ error = goodix_i2c_test(client); -+ if (error) { -+ dev_err(&client->dev, "I2C communication failure: %d\n", error); -+ return error; -+ } -+ -+ error = goodix_read_version(client, &version_info); -+ if (error) { -+ dev_err(&client->dev, "Read version failed.\n"); -+ return error; -+ } -+ -+ goodix_read_config(ts); -+ -+ error = goodix_request_input_dev(ts); -+ if (error) -+ return error; -+ -+ irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; -+ error = devm_request_threaded_irq(&ts->client->dev, client->irq, -+ NULL, goodix_ts_irq_handler, -+ irq_flags, client->name, ts); -+ if (error) { -+ dev_err(&client->dev, "request IRQ failed: %d\n", error); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static const struct i2c_device_id goodix_ts_id[] = { -+ { "GDIX1001:00", 0 }, -+ { } -+}; -+ -+static const struct acpi_device_id goodix_acpi_match[] = { -+ { "GDIX1001", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); -+ -+static struct i2c_driver goodix_ts_driver = { -+ .probe = goodix_ts_probe, -+ .id_table = goodix_ts_id, -+ .driver = { -+ .name = "Goodix-TS", -+ .owner = THIS_MODULE, -+ .acpi_match_table = goodix_acpi_match, -+ }, -+}; -+module_i2c_driver(goodix_ts_driver); -+ -+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); -+MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>"); -+MODULE_DESCRIPTION("Goodix touchscreen driver"); -+MODULE_LICENSE("GPL v2"); --- -2.1.0 - |