|
|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_device.h>
|
|
|
+#include <linux/sort.h>
|
|
|
|
|
|
#include <linux/mfd/ti_am335x_tscadc.h>
|
|
|
|
|
|
@@ -204,56 +205,61 @@ static void titsc_step_config(struct titsc *ts_dev)
|
|
|
am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
|
|
|
}
|
|
|
|
|
|
+static int titsc_cmp_coord(const void *a, const void *b)
|
|
|
+{
|
|
|
+ return *(int *)a - *(int *)b;
|
|
|
+}
|
|
|
+
|
|
|
static void titsc_read_coordinates(struct titsc *ts_dev,
|
|
|
u32 *x, u32 *y, u32 *z1, u32 *z2)
|
|
|
{
|
|
|
- unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
|
|
|
- unsigned int prev_val_x = ~0, prev_val_y = ~0;
|
|
|
- unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
|
|
|
- unsigned int read, diff;
|
|
|
- unsigned int i, channel;
|
|
|
+ unsigned int yvals[7], xvals[7];
|
|
|
+ unsigned int i, xsum = 0, ysum = 0;
|
|
|
unsigned int creads = ts_dev->coordinate_readouts;
|
|
|
- unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2);
|
|
|
|
|
|
- *z1 = *z2 = 0;
|
|
|
- if (fifocount % (creads * 2 + 2))
|
|
|
- fifocount -= fifocount % (creads * 2 + 2);
|
|
|
- /*
|
|
|
- * Delta filter is used to remove large variations in sampled
|
|
|
- * values from ADC. The filter tries to predict where the next
|
|
|
- * coordinate could be. This is done by taking a previous
|
|
|
- * coordinate and subtracting it form current one. Further the
|
|
|
- * algorithm compares the difference with that of a present value,
|
|
|
- * if true the value is reported to the sub system.
|
|
|
- */
|
|
|
- for (i = 0; i < fifocount; i++) {
|
|
|
- read = titsc_readl(ts_dev, REG_FIFO0);
|
|
|
-
|
|
|
- channel = (read & 0xf0000) >> 16;
|
|
|
- read &= 0xfff;
|
|
|
- if (channel > first_step + creads + 2) {
|
|
|
- diff = abs(read - prev_val_x);
|
|
|
- if (diff < prev_diff_x) {
|
|
|
- prev_diff_x = diff;
|
|
|
- *x = read;
|
|
|
- }
|
|
|
- prev_val_x = read;
|
|
|
+ for (i = 0; i < creads; i++) {
|
|
|
+ yvals[i] = titsc_readl(ts_dev, REG_FIFO0);
|
|
|
+ yvals[i] &= 0xfff;
|
|
|
+ }
|
|
|
|
|
|
- } else if (channel == first_step + creads + 1) {
|
|
|
- *z1 = read;
|
|
|
+ *z1 = titsc_readl(ts_dev, REG_FIFO0);
|
|
|
+ *z1 &= 0xfff;
|
|
|
+ *z2 = titsc_readl(ts_dev, REG_FIFO0);
|
|
|
+ *z2 &= 0xfff;
|
|
|
|
|
|
- } else if (channel == first_step + creads + 2) {
|
|
|
- *z2 = read;
|
|
|
+ for (i = 0; i < creads; i++) {
|
|
|
+ xvals[i] = titsc_readl(ts_dev, REG_FIFO0);
|
|
|
+ xvals[i] &= 0xfff;
|
|
|
+ }
|
|
|
|
|
|
- } else if (channel > first_step) {
|
|
|
- diff = abs(read - prev_val_y);
|
|
|
- if (diff < prev_diff_y) {
|
|
|
- prev_diff_y = diff;
|
|
|
- *y = read;
|
|
|
- }
|
|
|
- prev_val_y = read;
|
|
|
+ /*
|
|
|
+ * If co-ordinates readouts is less than 4 then
|
|
|
+ * report the average. In case of 4 or more
|
|
|
+ * readouts, sort the co-ordinate samples, drop
|
|
|
+ * min and max values and report the average of
|
|
|
+ * remaining values.
|
|
|
+ */
|
|
|
+ if (creads <= 3) {
|
|
|
+ for (i = 0; i < creads; i++) {
|
|
|
+ ysum += yvals[i];
|
|
|
+ xsum += xvals[i];
|
|
|
}
|
|
|
+ ysum /= creads;
|
|
|
+ xsum /= creads;
|
|
|
+ } else {
|
|
|
+ sort(yvals, creads, sizeof(unsigned int),
|
|
|
+ titsc_cmp_coord, NULL);
|
|
|
+ sort(xvals, creads, sizeof(unsigned int),
|
|
|
+ titsc_cmp_coord, NULL);
|
|
|
+ for (i = 1; i < creads - 1; i++) {
|
|
|
+ ysum += yvals[i];
|
|
|
+ xsum += xvals[i];
|
|
|
+ }
|
|
|
+ ysum /= creads - 2;
|
|
|
+ xsum /= creads - 2;
|
|
|
}
|
|
|
+ *y = ysum;
|
|
|
+ *x = xsum;
|
|
|
}
|
|
|
|
|
|
static irqreturn_t titsc_irq(int irq, void *dev)
|
|
|
@@ -369,6 +375,12 @@ static int titsc_parse_dt(struct platform_device *pdev,
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|
|
|
+ if (ts_dev->coordinate_readouts <= 0) {
|
|
|
+ dev_warn(&pdev->dev,
|
|
|
+ "invalid co-ordinate readouts, resetting it to 5\n");
|
|
|
+ ts_dev->coordinate_readouts = 5;
|
|
|
+ }
|
|
|
+
|
|
|
err = of_property_read_u32(node, "ti,charge-delay",
|
|
|
&ts_dev->charge_delay);
|
|
|
/*
|