aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVignesh R <vigneshr@ti.com>2015-02-03 14:47:05 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-03 14:50:39 -0500
commit83edfdf30b6f8d0916e8283fb395589afb9bdacb (patch)
tree450e8646f652f78198aa37e396e0f975b3454c35
parente6e4a0d1981febe1188f997e1b4fae0bb40a6e8c (diff)
Input: ti_am335x_tsc - replace delta filtering with median filtering
Previously, delta filtering was applied TSC co-ordinate readouts before reporting a single value to user space. This patch replaces delta filtering with median filtering. Median filtering sorts co-ordinate readouts, drops min and max values, and reports the average of remaining values. This method is more sensible than delta filtering. Median filtering is applied only if number of readouts is greater than 3 else just average of co-ordinate readouts is reported. Signed-off-by: Vignesh R <vigneshr@ti.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c92
1 files changed, 52 insertions, 40 deletions
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 7c0f6b21559d..191a1b87895f 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -26,6 +26,7 @@
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/of.h> 27#include <linux/of.h>
28#include <linux/of_device.h> 28#include <linux/of_device.h>
29#include <linux/sort.h>
29 30
30#include <linux/mfd/ti_am335x_tscadc.h> 31#include <linux/mfd/ti_am335x_tscadc.h>
31 32
@@ -204,56 +205,61 @@ static void titsc_step_config(struct titsc *ts_dev)
204 am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); 205 am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
205} 206}
206 207
208static int titsc_cmp_coord(const void *a, const void *b)
209{
210 return *(int *)a - *(int *)b;
211}
212
207static void titsc_read_coordinates(struct titsc *ts_dev, 213static void titsc_read_coordinates(struct titsc *ts_dev,
208 u32 *x, u32 *y, u32 *z1, u32 *z2) 214 u32 *x, u32 *y, u32 *z1, u32 *z2)
209{ 215{
210 unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); 216 unsigned int yvals[7], xvals[7];
211 unsigned int prev_val_x = ~0, prev_val_y = ~0; 217 unsigned int i, xsum = 0, ysum = 0;
212 unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
213 unsigned int read, diff;
214 unsigned int i, channel;
215 unsigned int creads = ts_dev->coordinate_readouts; 218 unsigned int creads = ts_dev->coordinate_readouts;
216 unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2);
217 219
218 *z1 = *z2 = 0; 220 for (i = 0; i < creads; i++) {
219 if (fifocount % (creads * 2 + 2)) 221 yvals[i] = titsc_readl(ts_dev, REG_FIFO0);
220 fifocount -= fifocount % (creads * 2 + 2); 222 yvals[i] &= 0xfff;
221 /* 223 }
222 * Delta filter is used to remove large variations in sampled
223 * values from ADC. The filter tries to predict where the next
224 * coordinate could be. This is done by taking a previous
225 * coordinate and subtracting it form current one. Further the
226 * algorithm compares the difference with that of a present value,
227 * if true the value is reported to the sub system.
228 */
229 for (i = 0; i < fifocount; i++) {
230 read = titsc_readl(ts_dev, REG_FIFO0);
231
232 channel = (read & 0xf0000) >> 16;
233 read &= 0xfff;
234 if (channel > first_step + creads + 2) {
235 diff = abs(read - prev_val_x);
236 if (diff < prev_diff_x) {
237 prev_diff_x = diff;
238 *x = read;
239 }
240 prev_val_x = read;
241 224
242 } else if (channel == first_step + creads + 1) { 225 *z1 = titsc_readl(ts_dev, REG_FIFO0);
243 *z1 = read; 226 *z1 &= 0xfff;
227 *z2 = titsc_readl(ts_dev, REG_FIFO0);
228 *z2 &= 0xfff;
244 229
245 } else if (channel == first_step + creads + 2) { 230 for (i = 0; i < creads; i++) {
246 *z2 = read; 231 xvals[i] = titsc_readl(ts_dev, REG_FIFO0);
232 xvals[i] &= 0xfff;
233 }
247 234
248 } else if (channel > first_step) { 235 /*
249 diff = abs(read - prev_val_y); 236 * If co-ordinates readouts is less than 4 then
250 if (diff < prev_diff_y) { 237 * report the average. In case of 4 or more
251 prev_diff_y = diff; 238 * readouts, sort the co-ordinate samples, drop
252 *y = read; 239 * min and max values and report the average of
253 } 240 * remaining values.
254 prev_val_y = read; 241 */
242 if (creads <= 3) {
243 for (i = 0; i < creads; i++) {
244 ysum += yvals[i];
245 xsum += xvals[i];
255 } 246 }
247 ysum /= creads;
248 xsum /= creads;
249 } else {
250 sort(yvals, creads, sizeof(unsigned int),
251 titsc_cmp_coord, NULL);
252 sort(xvals, creads, sizeof(unsigned int),
253 titsc_cmp_coord, NULL);
254 for (i = 1; i < creads - 1; i++) {
255 ysum += yvals[i];
256 xsum += xvals[i];
257 }
258 ysum /= creads - 2;
259 xsum /= creads - 2;
256 } 260 }
261 *y = ysum;
262 *x = xsum;
257} 263}
258 264
259static irqreturn_t titsc_irq(int irq, void *dev) 265static irqreturn_t titsc_irq(int irq, void *dev)
@@ -369,6 +375,12 @@ static int titsc_parse_dt(struct platform_device *pdev,
369 if (err < 0) 375 if (err < 0)
370 return err; 376 return err;
371 377
378 if (ts_dev->coordinate_readouts <= 0) {
379 dev_warn(&pdev->dev,
380 "invalid co-ordinate readouts, resetting it to 5\n");
381 ts_dev->coordinate_readouts = 5;
382 }
383
372 err = of_property_read_u32(node, "ti,charge-delay", 384 err = of_property_read_u32(node, "ti,charge-delay",
373 &ts_dev->charge_delay); 385 &ts_dev->charge_delay);
374 /* 386 /*