Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vignesh R and committed by
Dmitry Torokhov
83edfdf3 e6e4a0d1

+56 -44
+56 -44
drivers/input/touchscreen/ti_am335x_tsc.c
··· 26 26 #include <linux/delay.h> 27 27 #include <linux/of.h> 28 28 #include <linux/of_device.h> 29 + #include <linux/sort.h> 29 30 30 31 #include <linux/mfd/ti_am335x_tscadc.h> 31 32 ··· 205 204 am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); 206 205 } 207 206 207 + static int titsc_cmp_coord(const void *a, const void *b) 208 + { 209 + return *(int *)a - *(int *)b; 210 + } 211 + 208 212 static void titsc_read_coordinates(struct titsc *ts_dev, 209 213 u32 *x, u32 *y, u32 *z1, u32 *z2) 210 214 { 211 - unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); 212 - unsigned int prev_val_x = ~0, prev_val_y = ~0; 213 - unsigned int prev_diff_x = ~0, prev_diff_y = ~0; 214 - unsigned int read, diff; 215 - unsigned int i, channel; 215 + unsigned int yvals[7], xvals[7]; 216 + unsigned int i, xsum = 0, ysum = 0; 216 217 unsigned int creads = ts_dev->coordinate_readouts; 217 - unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2); 218 218 219 - *z1 = *z2 = 0; 220 - if (fifocount % (creads * 2 + 2)) 221 - fifocount -= fifocount % (creads * 2 + 2); 222 - /* 223 - * Delta filter is used to remove large variations in sampled 224 - * values from ADC. The filter tries to predict where the next 225 - * coordinate could be. This is done by taking a previous 226 - * coordinate and subtracting it form current one. Further the 227 - * algorithm compares the difference with that of a present value, 228 - * if true the value is reported to the sub system. 229 - */ 230 - for (i = 0; i < fifocount; i++) { 231 - read = titsc_readl(ts_dev, REG_FIFO0); 232 - 233 - channel = (read & 0xf0000) >> 16; 234 - read &= 0xfff; 235 - if (channel > first_step + creads + 2) { 236 - diff = abs(read - prev_val_x); 237 - if (diff < prev_diff_x) { 238 - prev_diff_x = diff; 239 - *x = read; 240 - } 241 - prev_val_x = read; 242 - 243 - } else if (channel == first_step + creads + 1) { 244 - *z1 = read; 245 - 246 - } else if (channel == first_step + creads + 2) { 247 - *z2 = read; 248 - 249 - } else if (channel > first_step) { 250 - diff = abs(read - prev_val_y); 251 - if (diff < prev_diff_y) { 252 - prev_diff_y = diff; 253 - *y = read; 254 - } 255 - prev_val_y = read; 256 - } 219 + for (i = 0; i < creads; i++) { 220 + yvals[i] = titsc_readl(ts_dev, REG_FIFO0); 221 + yvals[i] &= 0xfff; 257 222 } 223 + 224 + *z1 = titsc_readl(ts_dev, REG_FIFO0); 225 + *z1 &= 0xfff; 226 + *z2 = titsc_readl(ts_dev, REG_FIFO0); 227 + *z2 &= 0xfff; 228 + 229 + for (i = 0; i < creads; i++) { 230 + xvals[i] = titsc_readl(ts_dev, REG_FIFO0); 231 + xvals[i] &= 0xfff; 232 + } 233 + 234 + /* 235 + * If co-ordinates readouts is less than 4 then 236 + * report the average. In case of 4 or more 237 + * readouts, sort the co-ordinate samples, drop 238 + * min and max values and report the average of 239 + * remaining values. 240 + */ 241 + if (creads <= 3) { 242 + for (i = 0; i < creads; i++) { 243 + ysum += yvals[i]; 244 + xsum += xvals[i]; 245 + } 246 + ysum /= creads; 247 + xsum /= creads; 248 + } else { 249 + sort(yvals, creads, sizeof(unsigned int), 250 + titsc_cmp_coord, NULL); 251 + sort(xvals, creads, sizeof(unsigned int), 252 + titsc_cmp_coord, NULL); 253 + for (i = 1; i < creads - 1; i++) { 254 + ysum += yvals[i]; 255 + xsum += xvals[i]; 256 + } 257 + ysum /= creads - 2; 258 + xsum /= creads - 2; 259 + } 260 + *y = ysum; 261 + *x = xsum; 258 262 } 259 263 260 264 static irqreturn_t titsc_irq(int irq, void *dev) ··· 374 368 375 369 if (err < 0) 376 370 return err; 371 + 372 + if (ts_dev->coordinate_readouts <= 0) { 373 + dev_warn(&pdev->dev, 374 + "invalid co-ordinate readouts, resetting it to 5\n"); 375 + ts_dev->coordinate_readouts = 5; 376 + } 377 377 378 378 err = of_property_read_u32(node, "ti,charge-delay", 379 379 &ts_dev->charge_delay);