Merge tag 'backport/v3.14.24-ltsi-rc1/phy-rcar-gen2-usb-to-v3.15' into backport/v3...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / input / mouse / synaptics.c
index 898e8bb..1e76eb8 100644 (file)
@@ -117,6 +117,32 @@ void synaptics_reset(struct psmouse *psmouse)
 }
 
 #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+struct min_max_quirk {
+       const char * const *pnp_ids;
+       int x_min, x_max, y_min, y_max;
+};
+
+static const struct min_max_quirk min_max_pnpid_table[] = {
+       {
+               (const char * const []){"LEN0033", NULL},
+               1024, 5052, 2258, 4832
+       },
+       {
+               (const char * const []){"LEN0035", "LEN0042", NULL},
+               1232, 5710, 1156, 4696
+       },
+       {
+               (const char * const []){"LEN0034", "LEN0036", "LEN0039",
+                                       "LEN2002", "LEN2004", NULL},
+               1024, 5112, 2024, 4832
+       },
+       {
+               (const char * const []){"LEN2001", NULL},
+               1024, 5022, 2508, 4832
+       },
+       { }
+};
+
 /* This list has been kindly provided by Synaptics. */
 static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0017",
@@ -129,11 +155,12 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN002D",
        "LEN002E",
        "LEN0033", /* Helix */
-       "LEN0034", /* T431s, T540, X1 Carbon 2nd */
+       "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */
        "LEN0035", /* X240 */
        "LEN0036", /* T440 */
        "LEN0037",
        "LEN0038",
+       "LEN0039", /* T440s */
        "LEN0041",
        "LEN0042", /* Yoga */
        "LEN0045",
@@ -142,8 +169,8 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0048",
        "LEN0049",
        "LEN2000",
-       "LEN2001",
-       "LEN2002",
+       "LEN2001", /* Edge E431 */
+       "LEN2002", /* Edge E531 */
        "LEN2003",
        "LEN2004", /* L440 */
        "LEN2005",
@@ -156,6 +183,18 @@ static const char * const topbuttonpad_pnp_ids[] = {
        NULL
 };
 
+static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
+{
+       int i;
+
+       if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4))
+               for (i = 0; ids[i]; i++)
+                       if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i]))
+                               return true;
+
+       return false;
+}
+
 /*****************************************************************************
  *     Synaptics communications functions
  ****************************************************************************/
@@ -304,20 +343,11 @@ static int synaptics_identify(struct psmouse *psmouse)
  * Resolution is left zero if touchpad does not support the query
  */
 
-static const int *quirk_min_max;
-
 static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
-
-       if (quirk_min_max) {
-               priv->x_min = quirk_min_max[0];
-               priv->x_max = quirk_min_max[1];
-               priv->y_min = quirk_min_max[2];
-               priv->y_max = quirk_min_max[3];
-               return 0;
-       }
+       int i;
 
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
@@ -329,6 +359,16 @@ static int synaptics_resolution(struct psmouse *psmouse)
                }
        }
 
+       for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
+               if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) {
+                       priv->x_min = min_max_pnpid_table[i].x_min;
+                       priv->x_max = min_max_pnpid_table[i].x_max;
+                       priv->y_min = min_max_pnpid_table[i].y_min;
+                       priv->y_max = min_max_pnpid_table[i].y_max;
+                       return 0;
+               }
+       }
+
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
            SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
@@ -587,10 +627,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                         ((buf[0] & 0x04) >> 1) |
                         ((buf[3] & 0x04) >> 2));
 
+               if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
+                       SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
+                   hw->w == 2) {
+                       synaptics_parse_agm(buf, priv, hw);
+                       return 1;
+               }
+
+               hw->x = (((buf[3] & 0x10) << 8) |
+                        ((buf[1] & 0x0f) << 8) |
+                        buf[4]);
+               hw->y = (((buf[3] & 0x20) << 7) |
+                        ((buf[1] & 0xf0) << 4) |
+                        buf[5]);
+               hw->z = buf[2];
+
                hw->left  = (buf[0] & 0x01) ? 1 : 0;
                hw->right = (buf[0] & 0x02) ? 1 : 0;
 
-               if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+               if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) {
+                       /*
+                        * ForcePads, like Clickpads, use middle button
+                        * bits to report primary button clicks.
+                        * Unfortunately they report primary button not
+                        * only when user presses on the pad above certain
+                        * threshold, but also when there are more than one
+                        * finger on the touchpad, which interferes with
+                        * out multi-finger gestures.
+                        */
+                       if (hw->z == 0) {
+                               /* No contacts */
+                               priv->press = priv->report_press = false;
+                       } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
+                               /*
+                                * Single-finger touch with pressure above
+                                * the threshold. If pressure stays long
+                                * enough, we'll start reporting primary
+                                * button. We rely on the device continuing
+                                * sending data even if finger does not
+                                * move.
+                                */
+                               if  (!priv->press) {
+                                       priv->press_start = jiffies;
+                                       priv->press = true;
+                               } else if (time_after(jiffies,
+                                               priv->press_start +
+                                                       msecs_to_jiffies(50))) {
+                                       priv->report_press = true;
+                               }
+                       } else {
+                               priv->press = false;
+                       }
+
+                       hw->left = priv->report_press;
+
+               } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
                        /*
                         * Clickpad's button is transmitted as middle button,
                         * however, since it is primary button, we will report
@@ -609,21 +700,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                        hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
                }
 
-               if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
-                       SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
-                   hw->w == 2) {
-                       synaptics_parse_agm(buf, priv, hw);
-                       return 1;
-               }
-
-               hw->x = (((buf[3] & 0x10) << 8) |
-                        ((buf[1] & 0x0f) << 8) |
-                        buf[4]);
-               hw->y = (((buf[3] & 0x20) << 7) |
-                        ((buf[1] & 0xf0) << 4) |
-                        buf[5]);
-               hw->z = buf[2];
-
                if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
                    ((buf[0] ^ buf[3]) & 0x02)) {
                        switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
@@ -1365,17 +1441,8 @@ static void set_input_params(struct psmouse *psmouse,
 
        if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
                __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
-               /* See if this buttonpad has a top button area */
-               if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) {
-                       for (i = 0; topbuttonpad_pnp_ids[i]; i++) {
-                               if (strstr(psmouse->ps2dev.serio->firmware_id,
-                                          topbuttonpad_pnp_ids[i])) {
-                                       __set_bit(INPUT_PROP_TOPBUTTONPAD,
-                                                 dev->propbit);
-                                       break;
-                               }
-                       }
-               }
+               if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids))
+                       __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
                /* Clickpads report only left button */
                __clear_bit(BTN_RIGHT, dev->keybit);
                __clear_bit(BTN_MIDDLE, dev->keybit);
@@ -1547,112 +1614,10 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
        { }
 };
 
-static const struct dmi_system_id min_max_dmi_table[] __initconst = {
-#if defined(CONFIG_DMI)
-       {
-               /* Lenovo ThinkPad Helix */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
-               },
-               .driver_data = (int []){1024, 5052, 2258, 4832},
-       },
-       {
-               /* Lenovo ThinkPad X240 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
-               },
-               .driver_data = (int []){1232, 5710, 1156, 4696},
-       },
-       {
-               /* Lenovo ThinkPad Edge E431 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Edge E431"),
-               },
-               .driver_data = (int []){1024, 5022, 2508, 4832},
-       },
-       {
-               /* Lenovo ThinkPad T431s */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T431"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo ThinkPad T440s */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo ThinkPad L440 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L440"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo ThinkPad T540p */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo ThinkPad L540 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L540"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo ThinkPad W540 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W540"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-       {
-               /* Lenovo Yoga S1 */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
-                                       "ThinkPad S1 Yoga"),
-               },
-               .driver_data = (int []){1232, 5710, 1156, 4696},
-       },
-       {
-               /* Lenovo ThinkPad X1 Carbon Haswell (3rd generation) */
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION,
-                                       "ThinkPad X1 Carbon 2nd"),
-               },
-               .driver_data = (int []){1024, 5112, 2024, 4832},
-       },
-#endif
-       { }
-};
-
 void __init synaptics_module_init(void)
 {
-       const struct dmi_system_id *min_max_dmi;
-
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
        broken_olpc_ec = dmi_check_system(olpc_dmi_table);
-
-       min_max_dmi = dmi_first_match(min_max_dmi_table);
-       if (min_max_dmi)
-               quirk_min_max = min_max_dmi->driver_data;
 }
 
 static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)