aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2011-03-17 01:11:25 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-03-17 02:29:22 -0400
commit71f80045d48f259ea423bae3c14c2361e010a9ce (patch)
tree0b5294909c6138af3eb2dff0ea96afa5cfd88ec3
parentdacb650f125c7dc7ead9735d081bc078325b6d23 (diff)
Input: tsc2005 - handle read errors from SPI layer
Tested-by: Aaro Koskinen <aaro.koskinen@nokia.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/touchscreen/tsc2005.c100
1 files changed, 81 insertions, 19 deletions
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 7a765339018..5a15919ec4c 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -146,7 +146,7 @@ struct tsc2005 {
146 void (*set_reset)(bool enable); 146 void (*set_reset)(bool enable);
147}; 147};
148 148
149static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) 149static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
150{ 150{
151 u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; 151 u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
152 struct spi_transfer xfer = { 152 struct spi_transfer xfer = {
@@ -155,13 +155,22 @@ static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
155 .bits_per_word = 8, 155 .bits_per_word = 8,
156 }; 156 };
157 struct spi_message msg; 157 struct spi_message msg;
158 int error;
158 159
159 spi_message_init(&msg); 160 spi_message_init(&msg);
160 spi_message_add_tail(&xfer, &msg); 161 spi_message_add_tail(&xfer, &msg);
161 spi_sync(ts->spi, &msg); 162
163 error = spi_sync(ts->spi, &msg);
164 if (error) {
165 dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n",
166 __func__, cmd, error);
167 return error;
168 }
169
170 return 0;
162} 171}
163 172
164static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) 173static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
165{ 174{
166 u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; 175 u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value;
167 struct spi_transfer xfer = { 176 struct spi_transfer xfer = {
@@ -170,10 +179,20 @@ static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
170 .bits_per_word = 24, 179 .bits_per_word = 24,
171 }; 180 };
172 struct spi_message msg; 181 struct spi_message msg;
182 int error;
173 183
174 spi_message_init(&msg); 184 spi_message_init(&msg);
175 spi_message_add_tail(&xfer, &msg); 185 spi_message_add_tail(&xfer, &msg);
176 spi_sync(ts->spi, &msg); 186
187 error = spi_sync(ts->spi, &msg);
188 if (error) {
189 dev_err(&ts->spi->dev,
190 "%s: failed, register: %x, value: %x, error: %d\n",
191 __func__, reg, value, error);
192 return error;
193 }
194
195 return 0;
177} 196}
178 197
179static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) 198static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
@@ -188,18 +207,23 @@ static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
188 rd->spi_xfer.cs_change = !last; 207 rd->spi_xfer.cs_change = !last;
189} 208}
190 209
191static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) 210static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value)
192{ 211{
193 struct tsc2005_spi_rd spi_rd; 212 struct tsc2005_spi_rd spi_rd;
194 struct spi_message msg; 213 struct spi_message msg;
214 int error;
195 215
196 tsc2005_setup_read(&spi_rd, reg, true); 216 tsc2005_setup_read(&spi_rd, reg, true);
197 217
198 spi_message_init(&msg); 218 spi_message_init(&msg);
199 spi_message_add_tail(&spi_rd.spi_xfer, &msg); 219 spi_message_add_tail(&spi_rd.spi_xfer, &msg);
200 spi_sync(ts->spi, &msg); 220
221 error = spi_sync(ts->spi, &msg);
222 if (error)
223 return error;
201 224
202 *value = spi_rd.spi_rx; 225 *value = spi_rd.spi_rx;
226 return 0;
203} 227}
204 228
205static void tsc2005_update_pen_state(struct tsc2005 *ts, 229static void tsc2005_update_pen_state(struct tsc2005 *ts,
@@ -232,6 +256,7 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
232 unsigned int pressure; 256 unsigned int pressure;
233 u32 x, y; 257 u32 x, y;
234 u32 z1, z2; 258 u32 z1, z2;
259 int error;
235 260
236 mutex_lock(&ts->mutex); 261 mutex_lock(&ts->mutex);
237 262
@@ -239,7 +264,10 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
239 goto out; 264 goto out;
240 265
241 /* read the coordinates */ 266 /* read the coordinates */
242 spi_sync(ts->spi, &ts->spi_read_msg); 267 error = spi_sync(ts->spi, &ts->spi_read_msg);
268 if (unlikely(error))
269 goto out;
270
243 x = ts->spi_x.spi_rx; 271 x = ts->spi_x.spi_rx;
244 y = ts->spi_y.spi_rx; 272 y = ts->spi_y.spi_rx;
245 z1 = ts->spi_z1.spi_rx; 273 z1 = ts->spi_z1.spi_rx;
@@ -392,7 +420,8 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
392 u16 temp_high; 420 u16 temp_high;
393 u16 temp_high_orig; 421 u16 temp_high_orig;
394 u16 temp_high_test; 422 u16 temp_high_test;
395 unsigned int result; 423 bool success = true;
424 int error;
396 425
397 mutex_lock(&ts->mutex); 426 mutex_lock(&ts->mutex);
398 427
@@ -400,34 +429,65 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
400 * Test TSC2005 communications via temp high register. 429 * Test TSC2005 communications via temp high register.
401 */ 430 */
402 tsc2005_disable(ts); 431 tsc2005_disable(ts);
403 result = 1; 432
404 tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); 433 error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
434 if (error) {
435 dev_warn(dev, "selftest failed: read error %d\n", error);
436 success = false;
437 goto out;
438 }
439
405 temp_high_test = (temp_high_orig - 1) & MAX_12BIT; 440 temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
406 tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); 441
407 tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); 442 error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test);
443 if (error) {
444 dev_warn(dev, "selftest failed: write error %d\n", error);
445 success = false;
446 goto out;
447 }
448
449 error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
450 if (error) {
451 dev_warn(dev, "selftest failed: read error %d after write\n",
452 error);
453 success = false;
454 goto out;
455 }
456
408 if (temp_high != temp_high_test) { 457 if (temp_high != temp_high_test) {
409 dev_warn(dev, "selftest failed: %d != %d\n", 458 dev_warn(dev, "selftest failed: %d != %d\n",
410 temp_high, temp_high_test); 459 temp_high, temp_high_test);
411 result = 0; 460 success = false;
412 } 461 }
413 462
414 /* hardware reset */ 463 /* hardware reset */
415 ts->set_reset(false); 464 ts->set_reset(false);
416 usleep_range(100, 500); /* only 10us required */ 465 usleep_range(100, 500); /* only 10us required */
417 ts->set_reset(true); 466 ts->set_reset(true);
418 tsc2005_enable(ts); 467
468 if (!success)
469 goto out;
419 470
420 /* test that the reset really happened */ 471 /* test that the reset really happened */
421 tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); 472 error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
473 if (error) {
474 dev_warn(dev, "selftest failed: read error %d after reset\n",
475 error);
476 success = false;
477 goto out;
478 }
479
422 if (temp_high != temp_high_orig) { 480 if (temp_high != temp_high_orig) {
423 dev_warn(dev, "selftest failed after reset: %d != %d\n", 481 dev_warn(dev, "selftest failed after reset: %d != %d\n",
424 temp_high, temp_high_orig); 482 temp_high, temp_high_orig);
425 result = 0; 483 success = false;
426 } 484 }
427 485
486out:
487 tsc2005_enable(ts);
428 mutex_unlock(&ts->mutex); 488 mutex_unlock(&ts->mutex);
429 489
430 return sprintf(buf, "%u\n", result); 490 return sprintf(buf, "%d\n", success);
431} 491}
432 492
433static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); 493static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL);
@@ -469,6 +529,7 @@ static void tsc2005_esd_timer(unsigned long data)
469static void tsc2005_esd_work(struct work_struct *work) 529static void tsc2005_esd_work(struct work_struct *work)
470{ 530{
471 struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); 531 struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work);
532 int error;
472 u16 r; 533 u16 r;
473 534
474 mutex_lock(&ts->mutex); 535 mutex_lock(&ts->mutex);
@@ -480,8 +541,9 @@ static void tsc2005_esd_work(struct work_struct *work)
480 * If we cannot read our known value from configuration register 0 then 541 * If we cannot read our known value from configuration register 0 then
481 * reset the controller as if from power-up and start scanning again. 542 * reset the controller as if from power-up and start scanning again.
482 */ 543 */
483 tsc2005_read(ts, TSC2005_REG_CFR0, &r); 544 error = tsc2005_read(ts, TSC2005_REG_CFR0, &r);
484 if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { 545 if (error ||
546 ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
485 dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); 547 dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n");
486 ts->set_reset(false); 548 ts->set_reset(false);
487 tsc2005_update_pen_state(ts, 0, 0, 0); 549 tsc2005_update_pen_state(ts, 0, 0, 0);