Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / input / mouse / elantech.c
index 1fb1a7b5a75480a8690ec6a3e29c5bdc1bec69d6..1913301df08f079425a5d6ae5ceb11124c45e3aa 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/input.h>
@@ -472,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
        input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
        input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
        input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
-       input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-       input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+       /* For clickpads map both buttons to BTN_LEFT */
+       if (etd->fw_version & 0x001000) {
+               input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
+       } else {
+               input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+               input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       }
+
        input_report_abs(dev, ABS_PRESSURE, pres);
        input_report_abs(dev, ABS_TOOL_WIDTH, width);
 
@@ -483,10 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
 static void elantech_input_sync_v4(struct psmouse *psmouse)
 {
        struct input_dev *dev = psmouse->dev;
+       struct elantech_data *etd = psmouse->private;
        unsigned char *packet = psmouse->packet;
 
-       input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-       input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       /* For clickpads map both buttons to BTN_LEFT */
+       if (etd->fw_version & 0x001000) {
+               input_report_key(dev, BTN_LEFT, packet[0] & 0x03);
+       } else {
+               input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+               input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       }
+
        input_mt_report_pointer_emulation(dev, true);
        input_sync(dev);
 }
@@ -801,7 +816,11 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
                break;
 
        case 3:
-               etd->reg_10 = 0x0b;
+               if (etd->set_hw_resolution)
+                       etd->reg_10 = 0x0b;
+               else
+                       etd->reg_10 = 0x01;
+
                if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
                        rc = -1;
 
@@ -1300,6 +1319,23 @@ static int elantech_reconnect(struct psmouse *psmouse)
        return 0;
 }
 
+/*
+ * Some hw_version 3 models go into error state when we try to set
+ * bit 3 and/or bit 1 of r10.
+ */
+static const struct dmi_system_id no_hw_res_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               /* Gigabyte U2442 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "U2442"),
+               },
+       },
+#endif
+       { }
+};
+
 /*
  * determine hardware version and set some properties according to it.
  */
@@ -1351,6 +1387,9 @@ static int elantech_set_properties(struct elantech_data *etd)
                        etd->reports_pressure = true;
        }
 
+       /* Enable real hardware resolution on hw_version 3 ? */
+       etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table);
+
        return 0;
 }