aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2013-05-29 08:46:21 -0400
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2013-06-12 12:50:22 -0400
commit8c896308feae7fb2e8da4ae4c09fe2d2ca18ad7b (patch)
treeed20601fe5b29721cb70717b62b099521ccc48b2 /drivers/input
parent9f99928fe0a03dd2ba5894b7bb942cc50b5d7c5e (diff)
input: ti_am335x_adc: use only FIFO0 and clean up a little
The driver programs a threshold of "coordinate_readouts" say 5. The REG_FIFO0THR registers says it should it be programmed to "threshold minus one". The driver does not expect just 5 coordinates but 5 * 2 + 2. Multiplied by two because 5 for X and 5 for Y and plus 2 because we have two Z. The whole thing kind of works because It reads the 5 coordinates for X and Y from FIFO0 and FIFO1 and the last element in each FIFO is ignored within the loop and read later. Nothing guaranties that FIFO1 is ready by the time it is read. In fact I could see that that FIFO1 reaturns for Y channels 8,9, 10, 12, 6 and for Y channel 7 for Z. The problem is that channel 7 and channel 12 got somehow mixed up. The other Problem is that FIFO1 is also used by the IIO part leading to wrong results if both (tsc & adc) are used. The patch tries to clean up the whole thing a little: - Remove the +1 and -1 in REG_STEPCONFIG, REG_STEPDELAY and its counter part in the for loop. This is just confusing. - Use only FIFO0 in TSC. The fifo has space for 64 entries so should be fine. - Read the whole FIFO in one function and check the channel. - in case we dawdle around, make sure we only read a multiple of our coordinate set. On the second interrupt we will cleanup the remaining enties. Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c78
1 files changed, 41 insertions, 37 deletions
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index ff3215ddf9f5..1bceb2591fc7 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -120,11 +120,9 @@ static int titsc_config_wires(struct titsc *ts_dev)
120static void titsc_step_config(struct titsc *ts_dev) 120static void titsc_step_config(struct titsc *ts_dev)
121{ 121{
122 unsigned int config; 122 unsigned int config;
123 unsigned int stepenable = 0; 123 int i;
124 int i, total_steps; 124 int end_step;
125 125 u32 stepenable;
126 /* Configure the Step registers */
127 total_steps = 2 * ts_dev->coordinate_readouts;
128 126
129 config = STEPCONFIG_MODE_HWSYNC | 127 config = STEPCONFIG_MODE_HWSYNC |
130 STEPCONFIG_AVG_16 | ts_dev->bit_xp; 128 STEPCONFIG_AVG_16 | ts_dev->bit_xp;
@@ -142,7 +140,9 @@ static void titsc_step_config(struct titsc *ts_dev)
142 break; 140 break;
143 } 141 }
144 142
145 for (i = 1; i <= ts_dev->coordinate_readouts; i++) { 143 /* 1 … coordinate_readouts is for X */
144 end_step = ts_dev->coordinate_readouts;
145 for (i = 0; i < end_step; i++) {
146 titsc_writel(ts_dev, REG_STEPCONFIG(i), config); 146 titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
147 titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); 147 titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
148 } 148 }
@@ -150,7 +150,7 @@ static void titsc_step_config(struct titsc *ts_dev)
150 config = 0; 150 config = 0;
151 config = STEPCONFIG_MODE_HWSYNC | 151 config = STEPCONFIG_MODE_HWSYNC |
152 STEPCONFIG_AVG_16 | ts_dev->bit_yn | 152 STEPCONFIG_AVG_16 | ts_dev->bit_yn |
153 STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; 153 STEPCONFIG_INM_ADCREFM;
154 switch (ts_dev->wires) { 154 switch (ts_dev->wires) {
155 case 4: 155 case 4:
156 config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); 156 config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
@@ -164,12 +164,13 @@ static void titsc_step_config(struct titsc *ts_dev)
164 break; 164 break;
165 } 165 }
166 166
167 for (i = (ts_dev->coordinate_readouts + 1); i <= total_steps; i++) { 167 /* coordinate_readouts … coordinate_readouts * 2 is for Y */
168 end_step = ts_dev->coordinate_readouts * 2;
169 for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
168 titsc_writel(ts_dev, REG_STEPCONFIG(i), config); 170 titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
169 titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); 171 titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
170 } 172 }
171 173
172 config = 0;
173 /* Charge step configuration */ 174 /* Charge step configuration */
174 config = ts_dev->bit_xp | ts_dev->bit_yn | 175 config = ts_dev->bit_xp | ts_dev->bit_yn |
175 STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | 176 STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
@@ -178,35 +179,39 @@ static void titsc_step_config(struct titsc *ts_dev)
178 titsc_writel(ts_dev, REG_CHARGECONFIG, config); 179 titsc_writel(ts_dev, REG_CHARGECONFIG, config);
179 titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); 180 titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
180 181
181 config = 0; 182 /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
182 /* Configure to calculate pressure */
183 config = STEPCONFIG_MODE_HWSYNC | 183 config = STEPCONFIG_MODE_HWSYNC |
184 STEPCONFIG_AVG_16 | ts_dev->bit_yp | 184 STEPCONFIG_AVG_16 | ts_dev->bit_yp |
185 ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | 185 ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
186 STEPCONFIG_INP(ts_dev->inp_xp); 186 STEPCONFIG_INP(ts_dev->inp_xp);
187 titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); 187 titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
188 titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), 188 titsc_writel(ts_dev, REG_STEPDELAY(end_step),
189 STEPCONFIG_OPENDLY); 189 STEPCONFIG_OPENDLY);
190 190
191 config |= STEPCONFIG_INP(ts_dev->inp_yn) | STEPCONFIG_FIFO1; 191 end_step++;
192 titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); 192 config |= STEPCONFIG_INP(ts_dev->inp_yn);
193 titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), 193 titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
194 titsc_writel(ts_dev, REG_STEPDELAY(end_step),
194 STEPCONFIG_OPENDLY); 195 STEPCONFIG_OPENDLY);
195 196
196 /* The steps1 … end and bit 0 for TS_Charge */ 197 /* The steps1 … end and bit 0 for TS_Charge */
197 stepenable = (1 << (total_steps + 2)) - 1; 198 stepenable = (1 << (end_step + 2)) - 1;
198 am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable); 199 am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
199} 200}
200 201
201static void titsc_read_coordinates(struct titsc *ts_dev, 202static void titsc_read_coordinates(struct titsc *ts_dev,
202 unsigned int *x, unsigned int *y) 203 u32 *x, u32 *y, u32 *z1, u32 *z2)
203{ 204{
204 unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); 205 unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
205 unsigned int prev_val_x = ~0, prev_val_y = ~0; 206 unsigned int prev_val_x = ~0, prev_val_y = ~0;
206 unsigned int prev_diff_x = ~0, prev_diff_y = ~0; 207 unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
207 unsigned int read, diff; 208 unsigned int read, diff;
208 unsigned int i, channel; 209 unsigned int i, channel;
210 unsigned int creads = ts_dev->coordinate_readouts;
209 211
212 *z1 = *z2 = 0;
213 if (fifocount % (creads * 2 + 2))
214 fifocount -= fifocount % (creads * 2 + 2);
210 /* 215 /*
211 * Delta filter is used to remove large variations in sampled 216 * Delta filter is used to remove large variations in sampled
212 * values from ADC. The filter tries to predict where the next 217 * values from ADC. The filter tries to predict where the next
@@ -215,32 +220,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
215 * algorithm compares the difference with that of a present value, 220 * algorithm compares the difference with that of a present value,
216 * if true the value is reported to the sub system. 221 * if true the value is reported to the sub system.
217 */ 222 */
218 for (i = 0; i < fifocount - 1; i++) { 223 for (i = 0; i < fifocount; i++) {
219 read = titsc_readl(ts_dev, REG_FIFO0); 224 read = titsc_readl(ts_dev, REG_FIFO0);
220 channel = read & 0xf0000; 225
221 channel = channel >> 0x10; 226 channel = (read & 0xf0000) >> 16;
222 if ((channel >= 0) && (channel < ts_dev->coordinate_readouts)) { 227 read &= 0xfff;
223 read &= 0xfff; 228 if (channel < creads) {
224 diff = abs(read - prev_val_x); 229 diff = abs(read - prev_val_x);
225 if (diff < prev_diff_x) { 230 if (diff < prev_diff_x) {
226 prev_diff_x = diff; 231 prev_diff_x = diff;
227 *x = read; 232 *x = read;
228 } 233 }
229 prev_val_x = read; 234 prev_val_x = read;
230 }
231 235
232 read = titsc_readl(ts_dev, REG_FIFO1); 236 } else if (channel < creads * 2) {
233 channel = read & 0xf0000;
234 channel = channel >> 0x10;
235 if ((channel >= ts_dev->coordinate_readouts) &&
236 (channel < (2 * ts_dev->coordinate_readouts - 1))) {
237 read &= 0xfff;
238 diff = abs(read - prev_val_y); 237 diff = abs(read - prev_val_y);
239 if (diff < prev_diff_y) { 238 if (diff < prev_diff_y) {
240 prev_diff_y = diff; 239 prev_diff_y = diff;
241 *y = read; 240 *y = read;
242 } 241 }
243 prev_val_y = read; 242 prev_val_y = read;
243
244 } else if (channel < creads * 2 + 1) {
245 *z1 = read;
246
247 } else if (channel < creads * 2 + 2) {
248 *z2 = read;
244 } 249 }
245 } 250 }
246} 251}
@@ -256,10 +261,8 @@ static irqreturn_t titsc_irq(int irq, void *dev)
256 261
257 status = titsc_readl(ts_dev, REG_IRQSTATUS); 262 status = titsc_readl(ts_dev, REG_IRQSTATUS);
258 if (status & IRQENB_FIFO0THRES) { 263 if (status & IRQENB_FIFO0THRES) {
259 titsc_read_coordinates(ts_dev, &x, &y);
260 264
261 z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; 265 titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
262 z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
263 266
264 if (ts_dev->pen_down && z1 != 0 && z2 != 0) { 267 if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
265 /* 268 /*
@@ -267,10 +270,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)
267 * Resistance(touch) = x plate resistance * 270 * Resistance(touch) = x plate resistance *
268 * x postion/4096 * ((z2 / z1) - 1) 271 * x postion/4096 * ((z2 / z1) - 1)
269 */ 272 */
270 z = z2 - z1; 273 z = z1 - z2;
271 z *= x; 274 z *= x;
272 z *= ts_dev->x_plate_resistance; 275 z *= ts_dev->x_plate_resistance;
273 z /= z1; 276 z /= z2;
274 z = (z + 2047) >> 12; 277 z = (z + 2047) >> 12;
275 278
276 if (z <= MAX_12BIT) { 279 if (z <= MAX_12BIT) {
@@ -391,7 +394,8 @@ static int titsc_probe(struct platform_device *pdev)
391 goto err_free_irq; 394 goto err_free_irq;
392 } 395 }
393 titsc_step_config(ts_dev); 396 titsc_step_config(ts_dev);
394 titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->coordinate_readouts); 397 titsc_writel(ts_dev, REG_FIFO0THR,
398 ts_dev->coordinate_readouts * 2 + 2 - 1);
395 399
396 input_dev->name = "ti-tsc"; 400 input_dev->name = "ti-tsc";
397 input_dev->dev.parent = &pdev->dev; 401 input_dev->dev.parent = &pdev->dev;
@@ -468,7 +472,7 @@ static int titsc_resume(struct device *dev)
468 } 472 }
469 titsc_step_config(ts_dev); 473 titsc_step_config(ts_dev);
470 titsc_writel(ts_dev, REG_FIFO0THR, 474 titsc_writel(ts_dev, REG_FIFO0THR,
471 ts_dev->coordinate_readouts); 475 ts_dev->coordinate_readouts * 2 + 2 - 1);
472 return 0; 476 return 0;
473} 477}
474 478