Input: elantech - add more IC body types to the list
[pandora-kernel.git] / drivers / input / mouse / elantech.c
index 3fee536..537692d 100644 (file)
@@ -296,7 +296,7 @@ static void elantech_report_semi_mt_data(struct input_dev *dev,
                                         unsigned int x2, unsigned int y2)
 {
        elantech_set_slot(dev, 0, num_fingers != 0, x1, y1);
-       elantech_set_slot(dev, 1, num_fingers == 2, x2, y2);
+       elantech_set_slot(dev, 1, num_fingers >= 2, x2, y2);
 }
 
 /*
@@ -692,18 +692,18 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
 static int elantech_packet_check_v4(struct psmouse *psmouse)
 {
        unsigned char *packet = psmouse->packet;
+       unsigned char packet_type = packet[3] & 0x03;
 
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x11)
+       switch (packet_type) {
+       case 0:
+               return PACKET_V4_STATUS;
+
+       case 1:
                return PACKET_V4_HEAD;
 
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x12)
+       case 2:
                return PACKET_V4_MOTION;
-
-       if ((packet[0] & 0x0c) == 0x04 &&
-           (packet[3] & 0x1f) == 0x10)
-               return PACKET_V4_STATUS;
+       }
 
        return PACKET_UNKNOWN;
 }
@@ -765,6 +765,21 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
        return PSMOUSE_FULL_PACKET;
 }
 
+/*
+ * This writes the reg_07 value again to the hardware at the end of every
+ * set_rate call because the register loses its value. reg_07 allows setting
+ * absolute mode on v4 hardware
+ */
+static void elantech_set_rate_restore_reg_07(struct psmouse *psmouse,
+               unsigned int rate)
+{
+       struct elantech_data *etd = psmouse->private;
+
+       etd->original_set_rate(psmouse, rate);
+       if (elantech_write_reg(psmouse, 0x07, etd->reg_07))
+               psmouse_err(psmouse, "restoring reg_07 failed\n");
+}
+
 /*
  * Put the touchpad into absolute mode
  */
@@ -801,7 +816,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
                if (etd->set_hw_resolution)
                        etd->reg_10 = 0x0b;
                else
-                       etd->reg_10 = 0x03;
+                       etd->reg_10 = 0x01;
 
                if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
                        rc = -1;
@@ -1130,6 +1145,14 @@ static bool elantech_is_signature_valid(const unsigned char *param)
        if (param[1] == 0)
                return true;
 
+       /*
+        * Some hw_version >= 4 models have a revision higher then 20. Meaning
+        * that param[2] may be 10 or 20, skip the rates check for these.
+        */
+       if ((param[0] & 0x0f) >= 0x06 && (param[1] & 0xaf) == 0x0f &&
+           param[2] < 40)
+               return true;
+
        for (i = 0; i < ARRAY_SIZE(rates); i++)
                if (param[2] == rates[i])
                        return false;
@@ -1225,7 +1248,8 @@ static int elantech_reconnect(struct psmouse *psmouse)
 }
 
 /*
- * Some hw_version 3 models go into error state when we try to set bit 3 of r10
+ * 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)
@@ -1260,7 +1284,7 @@ static int elantech_set_properties(struct elantech_data *etd)
                case 5:
                        etd->hw_version = 3;
                        break;
-               case 6:
+               case 6 ... 14:
                        etd->hw_version = 4;
                        break;
                default:
@@ -1345,6 +1369,11 @@ int elantech_init(struct psmouse *psmouse)
                goto init_fail;
        }
 
+       if (etd->fw_version == 0x381f17) {
+               etd->original_set_rate = psmouse->set_rate;
+               psmouse->set_rate = elantech_set_rate_restore_reg_07;
+       }
+
        if (elantech_set_input_params(psmouse)) {
                psmouse_err(psmouse, "failed to query touchpad range.\n");
                goto init_fail;