These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / input / touchscreen / goodix.c
index 3af1698..4d113c9 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/dmi.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
@@ -34,6 +35,7 @@ struct goodix_ts_data {
        int abs_y_max;
        unsigned int max_touch_num;
        unsigned int int_trigger_type;
+       bool rotated_screen;
 };
 
 #define GOODIX_MAX_HEIGHT              4096
@@ -47,7 +49,7 @@ struct goodix_ts_data {
 /* Register defines */
 #define GOODIX_READ_COOR_ADDR          0x814E
 #define GOODIX_REG_CONFIG_DATA         0x8047
-#define GOODIX_REG_VERSION             0x8140
+#define GOODIX_REG_ID                  0x8140
 
 #define RESOLUTION_LOC         1
 #define MAX_CONTACTS_LOC       5
@@ -60,6 +62,30 @@ static const unsigned long goodix_irq_flags[] = {
        IRQ_TYPE_LEVEL_HIGH,
 };
 
+/*
+ * Those tablets have their coordinates origin at the bottom right
+ * of the tablet, as if rotated 180 degrees
+ */
+static const struct dmi_system_id rotated_screen[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               .ident = "WinBook TW100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
+               }
+       },
+       {
+               .ident = "WinBook TW700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
+               },
+       },
+#endif
+       {}
+};
+
 /**
  * goodix_i2c_read - read data from a register of the i2c slave device.
  *
@@ -69,7 +95,7 @@ static const unsigned long goodix_irq_flags[] = {
  * @len: length of the buffer to write
  */
 static int goodix_i2c_read(struct i2c_client *client,
-                               u16 reg, u8 *buf, int len)
+                          u16 reg, u8 *buf, int len)
 {
        struct i2c_msg msgs[2];
        u16 wbuf = cpu_to_be16(reg);
@@ -78,7 +104,7 @@ static int goodix_i2c_read(struct i2c_client *client,
        msgs[0].flags = 0;
        msgs[0].addr  = client->addr;
        msgs[0].len   = 2;
-       msgs[0].buf   = (u8 *) &wbuf;
+       msgs[0].buf   = (u8 *)&wbuf;
 
        msgs[1].flags = I2C_M_RD;
        msgs[1].addr  = client->addr;
@@ -101,6 +127,9 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
                return error;
        }
 
+       if (!(data[0] & 0x80))
+               return -EAGAIN;
+
        touch_num = data[0] & 0x0f;
        if (touch_num > ts->max_touch_num)
                return -EPROTO;
@@ -126,6 +155,11 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
        int input_y = get_unaligned_le16(&coor_data[3]);
        int input_w = get_unaligned_le16(&coor_data[5]);
 
+       if (ts->rotated_screen) {
+               input_x = ts->abs_x_max - input_x;
+               input_y = ts->abs_y_max - input_y;
+       }
+
        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);
@@ -144,7 +178,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
  */
 static void goodix_process_events(struct goodix_ts_data *ts)
 {
-       u8  point_data[1 + GOODIX_CONTACT_SIZE * ts->max_touch_num];
+       u8  point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
        int touch_num;
        int i;
 
@@ -196,8 +230,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
        int error;
 
        error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
-                             config,
-                          GOODIX_CONFIG_MAX_LENGTH);
+                               config,
+                               GOODIX_CONFIG_MAX_LENGTH);
        if (error) {
                dev_warn(&ts->client->dev,
                         "Error reading config (%d), using defaults\n",
@@ -220,6 +254,11 @@ static void goodix_read_config(struct goodix_ts_data *ts)
                ts->abs_y_max = GOODIX_MAX_HEIGHT;
                ts->max_touch_num = GOODIX_MAX_CONTACTS;
        }
+
+       ts->rotated_screen = dmi_check_system(rotated_screen);
+       if (ts->rotated_screen)
+               dev_dbg(&ts->client->dev,
+                        "Applying '180 degrees rotated screen' quirk\n");
 }
 
 /**
@@ -227,22 +266,28 @@ static void goodix_read_config(struct goodix_ts_data *ts)
  *
  * @client: the i2c client
  * @version: output buffer containing the version on success
+ * @id: output buffer containing the id on success
  */
-static int goodix_read_version(struct i2c_client *client, u16 *version)
+static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
 {
        int error;
        u8 buf[6];
+       char id_str[5];
 
-       error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
+       error = goodix_i2c_read(client, GOODIX_REG_ID, 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]);
+       memcpy(id_str, buf, 4);
+       id_str[4] = 0;
+       if (kstrtou16(id_str, 10, id))
+               *id = 0x1001;
+
+       *version = get_unaligned_le16(&buf[4]);
 
-       dev_info(&client->dev, "IC VERSION: %6ph\n", buf);
+       dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
 
        return 0;
 }
@@ -276,10 +321,13 @@ static int goodix_i2c_test(struct i2c_client *client)
  * goodix_request_input_dev - Allocate, populate and register the input device
  *
  * @ts: our goodix_ts_data pointer
+ * @version: device firmware version
+ * @id: device ID
  *
  * Must be called during probe
  */
-static int goodix_request_input_dev(struct goodix_ts_data *ts)
+static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
+                                   u16 id)
 {
        int error;
 
@@ -289,14 +337,10 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
                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_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);
 
@@ -307,8 +351,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
        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;
+       ts->input_dev->id.product = id;
+       ts->input_dev->id.version = version;
 
        error = input_register_device(ts->input_dev);
        if (error) {
@@ -326,7 +370,7 @@ static int goodix_ts_probe(struct i2c_client *client,
        struct goodix_ts_data *ts;
        unsigned long irq_flags;
        int error;
-       u16 version_info;
+       u16 version_info, id_info;
 
        dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
 
@@ -348,7 +392,7 @@ static int goodix_ts_probe(struct i2c_client *client,
                return error;
        }
 
-       error = goodix_read_version(client, &version_info);
+       error = goodix_read_version(client, &version_info, &id_info);
        if (error) {
                dev_err(&client->dev, "Read version failed.\n");
                return error;
@@ -356,7 +400,7 @@ static int goodix_ts_probe(struct i2c_client *client,
 
        goodix_read_config(ts);
 
-       error = goodix_request_input_dev(ts);
+       error = goodix_request_input_dev(ts, version_info, id_info);
        if (error)
                return error;
 
@@ -376,6 +420,7 @@ static const struct i2c_device_id goodix_ts_id[] = {
        { "GDIX1001:00", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id goodix_acpi_match[] = {
@@ -404,7 +449,6 @@ static struct i2c_driver goodix_ts_driver = {
        .id_table = goodix_ts_id,
        .driver = {
                .name = "Goodix-TS",
-               .owner = THIS_MODULE,
                .acpi_match_table = ACPI_PTR(goodix_acpi_match),
                .of_match_table = of_match_ptr(goodix_of_match),
        },