Merge tag 'for-linus-20151106' of git://git.infradead.org/linux-mtd
[firefly-linux-kernel-4.4.55.git] / drivers / input / mouse / appletouch.c
index 800ca7dfafc2b79350c879e168dfc5731fab518c..ef234c9b2f2f5cce7e365951df37cef4bc8b08e4 100644 (file)
@@ -48,6 +48,7 @@ struct atp_info {
        int yfact;                              /* Y multiplication factor */
        int datalen;                            /* size of USB transfers */
        void (*callback)(struct urb *);         /* callback function */
+       int fuzz;                               /* fuzz touchpad generates */
 };
 
 static void atp_complete_geyser_1_2(struct urb *urb);
@@ -61,6 +62,7 @@ static const struct atp_info fountain_info = {
        .yfact          = 43,
        .datalen        = 81,
        .callback       = atp_complete_geyser_1_2,
+       .fuzz           = 16,
 };
 
 static const struct atp_info geyser1_info = {
@@ -71,6 +73,7 @@ static const struct atp_info geyser1_info = {
        .yfact          = 43,
        .datalen        = 81,
        .callback       = atp_complete_geyser_1_2,
+       .fuzz           = 16,
 };
 
 static const struct atp_info geyser2_info = {
@@ -81,6 +84,7 @@ static const struct atp_info geyser2_info = {
        .yfact          = 43,
        .datalen        = 64,
        .callback       = atp_complete_geyser_1_2,
+       .fuzz           = 0,
 };
 
 static const struct atp_info geyser3_info = {
@@ -90,6 +94,7 @@ static const struct atp_info geyser3_info = {
        .yfact          = 64,
        .datalen        = 64,
        .callback       = atp_complete_geyser_3_4,
+       .fuzz           = 0,
 };
 
 static const struct atp_info geyser4_info = {
@@ -99,6 +104,7 @@ static const struct atp_info geyser4_info = {
        .yfact          = 64,
        .datalen        = 64,
        .callback       = atp_complete_geyser_3_4,
+       .fuzz           = 0,
 };
 
 #define ATP_DEVICE(prod, info)                                 \
@@ -155,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);
 #define ATP_XSENSORS   26
 #define ATP_YSENSORS   16
 
-/* amount of fuzz this touchpad generates */
-#define ATP_FUZZ       16
+/*
+ * The largest possible bank of sensors with additional buffer of 4 extra values
+ * on either side, for an array of smoothed sensor values.
+ */
+#define ATP_SMOOTHSIZE 34
 
 /* maximum pressure this driver will report */
 #define ATP_PRESSURE   300
@@ -165,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);
  * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
  * ignored.
  */
-#define ATP_THRESHOLD   5
+#define ATP_THRESHOLD  5
+
+/*
+ * How far we'll bitshift our sensor values before averaging them. Mitigates
+ * rounding errors.
+ */
+#define ATP_SCALE      12
 
 /* Geyser initialization constants */
 #define ATP_GEYSER_MODE_READ_REQUEST_ID                1
@@ -203,11 +218,14 @@ struct atp {
        bool                    valid;          /* are the samples valid? */
        bool                    size_detect_done;
        bool                    overflow_warned;
+       int                     fingers_old;    /* last reported finger count */
        int                     x_old;          /* last reported x/y, */
        int                     y_old;          /* used for smoothing */
        signed char             xy_cur[ATP_XSENSORS + ATP_YSENSORS];
        signed char             xy_old[ATP_XSENSORS + ATP_YSENSORS];
        int                     xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+       int                     smooth[ATP_SMOOTHSIZE];
+       int                     smooth_tmp[ATP_SMOOTHSIZE];
        int                     idlecount;      /* number of empty packets */
        struct work_struct      work;
 };
@@ -326,10 +344,17 @@ static void atp_reinit(struct work_struct *work)
                        retval);
 }
 
-static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
-                            int *z, int *fingers)
+static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors,
+                            int fact, int *z, int *fingers)
 {
-       int i;
+       int i, pass;
+
+       /*
+        * Use offset to point xy_sensors at the first value in dev->xy_acc
+        * for whichever dimension we're looking at this particular go-round.
+        */
+       int *xy_sensors = dev->xy_acc + offset;
+
        /* values to calculate mean */
        int pcum = 0, psum = 0;
        int is_increasing = 0;
@@ -341,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
                        if (is_increasing)
                                is_increasing = 0;
 
-                       continue;
-               }
-
                /*
                 * Makes the finger detection more versatile.  For example,
                 * two fingers with no gap will be detected.  Also, my
@@ -358,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
                 *
                 * - Jason Parekh <jasonparekh@gmail.com>
                 */
-               if (i < 1 ||
+
+               } else if (i < 1 ||
                    (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
                        (*fingers)++;
                        is_increasing = 1;
                } else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
                        is_increasing = 0;
                }
+       }
+
+       if (*fingers < 1)     /* No need to continue if no fingers are found. */
+               return 0;
 
+       /*
+        * Use a smoothed version of sensor data for movement calculations, to
+        * combat noise without needing to rely so heavily on a threshold.
+        * This improves tracking.
+        *
+        * The smoothed array is bigger than the original so that the smoothing
+        * doesn't result in edge values being truncated.
+        */
+
+       memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0]));
+       /* Pull base values, scaled up to help avoid truncation errors. */
+       for (i = 0; i < nb_sensors; i++)
+               dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE;
+       memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0]));
+
+       for (pass = 0; pass < 4; pass++) {
+               /* Handle edge. */
+               dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2;
+
+               /* Average values with neighbors. */
+               for (i = 1; i < nb_sensors + 7; i++)
+                       dev->smooth_tmp[i] = (dev->smooth[i - 1] +
+                                             dev->smooth[i] * 2 +
+                                             dev->smooth[i + 1]) / 4;
+
+               /* Handle other edge. */
+               dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2;
+
+               memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth));
+       }
+
+       for (i = 0; i < nb_sensors + 8; i++) {
                /*
-                * Subtracts threshold so a high sensor that just passes the
-                * threshold won't skew the calculated absolute coordinate.
-                * Fixes an issue where slowly moving the mouse would
-                * occasionally jump a number of pixels (slowly moving the
-                * finger makes this issue most apparent.)
+                * Skip values if they're small enough to be truncated to 0
+                * by scale. Mostly noise.
                 */
-               pcum += (xy_sensors[i] - threshold) * i;
-               psum += (xy_sensors[i] - threshold);
+               if ((dev->smooth[i] >> ATP_SCALE) > 0) {
+                       pcum += dev->smooth[i] * i;
+                       psum += dev->smooth[i];
+               }
        }
 
        if (psum > 0) {
-               *z = psum;
+               *z = psum >> ATP_SCALE;        /* Scale down pressure output. */
                return pcum * fact / psum;
        }
 
@@ -455,7 +513,7 @@ static void atp_detect_size(struct atp *dev)
                        input_set_abs_params(dev->input, ABS_X, 0,
                                             (dev->info->xsensors_17 - 1) *
                                                        dev->info->xfact - 1,
-                                            ATP_FUZZ, 0);
+                                            dev->info->fuzz, 0);
                        break;
                }
        }
@@ -471,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
 {
        int x, y, x_z, y_z, x_f, y_f;
        int retval, i, j;
-       int key;
+       int key, fingers;
        struct atp *dev = urb->context;
        int status = atp_status_check(urb);
 
@@ -548,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)
 
        dbg_dump("accumulator", dev->xy_acc);
 
-       x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+       x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
                              dev->info->xfact, &x_z, &x_f);
-       y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+       y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
                              dev->info->yfact, &y_z, &y_f);
        key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
 
-       if (x && y) {
+       fingers = max(x_f, y_f);
+
+       if (x && y && fingers == dev->fingers_old) {
                if (dev->x_old != -1) {
-                       x = (dev->x_old * 3 + x) >> 2;
-                       y = (dev->y_old * 3 + y) >> 2;
+                       x = (dev->x_old * 7 + x) >> 3;
+                       y = (dev->y_old * 7 + y) >> 3;
                        dev->x_old = x;
                        dev->y_old = y;
 
@@ -571,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
                        input_report_abs(dev->input, ABS_Y, y);
                        input_report_abs(dev->input, ABS_PRESSURE,
                                         min(ATP_PRESSURE, x_z + y_z));
-                       atp_report_fingers(dev->input, max(x_f, y_f));
+                       atp_report_fingers(dev->input, fingers);
                }
                dev->x_old = x;
                dev->y_old = y;
@@ -579,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
        } else if (!x && !y) {
 
                dev->x_old = dev->y_old = -1;
+               dev->fingers_old = 0;
                input_report_key(dev->input, BTN_TOUCH, 0);
                input_report_abs(dev->input, ABS_PRESSURE, 0);
                atp_report_fingers(dev->input, 0);
@@ -587,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
                memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
        }
 
+       if (fingers != dev->fingers_old)
+               dev->x_old = dev->y_old = -1;
+       dev->fingers_old = fingers;
+
        input_report_key(dev->input, BTN_LEFT, key);
        input_sync(dev->input);
 
@@ -604,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
 {
        int x, y, x_z, y_z, x_f, y_f;
        int retval, i, j;
-       int key;
+       int key, fingers;
        struct atp *dev = urb->context;
        int status = atp_status_check(urb);
 
@@ -660,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)
 
        dbg_dump("accumulator", dev->xy_acc);
 
-       x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+       x = atp_calculate_abs(dev, 0, ATP_XSENSORS,
                              dev->info->xfact, &x_z, &x_f);
-       y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+       y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,
                              dev->info->yfact, &y_z, &y_f);
+
        key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
 
-       if (x && y) {
+       fingers = max(x_f, y_f);
+
+       if (x && y && fingers == dev->fingers_old) {
                if (dev->x_old != -1) {
-                       x = (dev->x_old * 3 + x) >> 2;
-                       y = (dev->y_old * 3 + y) >> 2;
+                       x = (dev->x_old * 7 + x) >> 3;
+                       y = (dev->y_old * 7 + y) >> 3;
                        dev->x_old = x;
                        dev->y_old = y;
 
@@ -683,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
                        input_report_abs(dev->input, ABS_Y, y);
                        input_report_abs(dev->input, ABS_PRESSURE,
                                         min(ATP_PRESSURE, x_z + y_z));
-                       atp_report_fingers(dev->input, max(x_f, y_f));
+                       atp_report_fingers(dev->input, fingers);
                }
                dev->x_old = x;
                dev->y_old = y;
@@ -691,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
        } else if (!x && !y) {
 
                dev->x_old = dev->y_old = -1;
+               dev->fingers_old = 0;
                input_report_key(dev->input, BTN_TOUCH, 0);
                input_report_abs(dev->input, ABS_PRESSURE, 0);
                atp_report_fingers(dev->input, 0);
@@ -699,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
                memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
        }
 
+       if (fingers != dev->fingers_old)
+               dev->x_old = dev->y_old = -1;
+       dev->fingers_old = fingers;
+
        input_report_key(dev->input, BTN_LEFT, key);
        input_sync(dev->input);
 
@@ -843,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,
 
        input_set_abs_params(input_dev, ABS_X, 0,
                             (dev->info->xsensors - 1) * dev->info->xfact - 1,
-                            ATP_FUZZ, 0);
+                            dev->info->fuzz, 0);
        input_set_abs_params(input_dev, ABS_Y, 0,
                             (dev->info->ysensors - 1) * dev->info->yfact - 1,
-                            ATP_FUZZ, 0);
+                            dev->info->fuzz, 0);
        input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
 
        set_bit(EV_KEY, input_dev->evbit);