diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2014-01-25 12:14:45 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-02-13 14:41:36 -0500 |
commit | 7d2eadc9b9d4eacc6aa8cc0cb33e05b5a6d30256 (patch) | |
tree | 65ad4af48a97e8ed4314ee19934a56173a98c24b /drivers/gpu/drm/i2c | |
parent | 2f7f730a4f0fd3376dda9266203f29ceccd0a67f (diff) |
drm/i2c: tda998x: check more I/O errors
This patch adds more error checking inn I2C I/O functions.
In case of I/O error, this permits to avoid writing in bad controller
pages, a bad chipset detection or looping when getting the EDID.
Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/gpu/drm/i2c')
-rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 7df73baf3f9b..9bd336cdb734 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -363,7 +363,7 @@ fail: | |||
363 | return 0; | 363 | return 0; |
364 | } | 364 | } |
365 | 365 | ||
366 | static void | 366 | static int |
367 | set_page(struct tda998x_priv *priv, uint16_t reg) | 367 | set_page(struct tda998x_priv *priv, uint16_t reg) |
368 | { | 368 | { |
369 | if (REG2PAGE(reg) != priv->current_page) { | 369 | if (REG2PAGE(reg) != priv->current_page) { |
@@ -372,11 +372,14 @@ set_page(struct tda998x_priv *priv, uint16_t reg) | |||
372 | REG_CURPAGE, REG2PAGE(reg) | 372 | REG_CURPAGE, REG2PAGE(reg) |
373 | }; | 373 | }; |
374 | int ret = i2c_master_send(client, buf, sizeof(buf)); | 374 | int ret = i2c_master_send(client, buf, sizeof(buf)); |
375 | if (ret < 0) | 375 | if (ret < 0) { |
376 | dev_err(&client->dev, "Error %d writing to REG_CURPAGE\n", ret); | 376 | dev_err(&client->dev, "Error %d writing to REG_CURPAGE\n", ret); |
377 | return ret; | ||
378 | } | ||
377 | 379 | ||
378 | priv->current_page = REG2PAGE(reg); | 380 | priv->current_page = REG2PAGE(reg); |
379 | } | 381 | } |
382 | return 0; | ||
380 | } | 383 | } |
381 | 384 | ||
382 | static int | 385 | static int |
@@ -386,7 +389,9 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) | |||
386 | uint8_t addr = REG2ADDR(reg); | 389 | uint8_t addr = REG2ADDR(reg); |
387 | int ret; | 390 | int ret; |
388 | 391 | ||
389 | set_page(priv, reg); | 392 | ret = set_page(priv, reg); |
393 | if (ret < 0) | ||
394 | return ret; | ||
390 | 395 | ||
391 | ret = i2c_master_send(client, &addr, sizeof(addr)); | 396 | ret = i2c_master_send(client, &addr, sizeof(addr)); |
392 | if (ret < 0) | 397 | if (ret < 0) |
@@ -413,18 +418,24 @@ reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt) | |||
413 | buf[0] = REG2ADDR(reg); | 418 | buf[0] = REG2ADDR(reg); |
414 | memcpy(&buf[1], p, cnt); | 419 | memcpy(&buf[1], p, cnt); |
415 | 420 | ||
416 | set_page(priv, reg); | 421 | ret = set_page(priv, reg); |
422 | if (ret < 0) | ||
423 | return; | ||
417 | 424 | ||
418 | ret = i2c_master_send(client, buf, cnt + 1); | 425 | ret = i2c_master_send(client, buf, cnt + 1); |
419 | if (ret < 0) | 426 | if (ret < 0) |
420 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); | 427 | dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); |
421 | } | 428 | } |
422 | 429 | ||
423 | static uint8_t | 430 | static int |
424 | reg_read(struct tda998x_priv *priv, uint16_t reg) | 431 | reg_read(struct tda998x_priv *priv, uint16_t reg) |
425 | { | 432 | { |
426 | uint8_t val = 0; | 433 | uint8_t val = 0; |
427 | reg_read_range(priv, reg, &val, sizeof(val)); | 434 | int ret; |
435 | |||
436 | ret = reg_read_range(priv, reg, &val, sizeof(val)); | ||
437 | if (ret < 0) | ||
438 | return ret; | ||
428 | return val; | 439 | return val; |
429 | } | 440 | } |
430 | 441 | ||
@@ -435,7 +446,9 @@ reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val) | |||
435 | uint8_t buf[] = {REG2ADDR(reg), val}; | 446 | uint8_t buf[] = {REG2ADDR(reg), val}; |
436 | int ret; | 447 | int ret; |
437 | 448 | ||
438 | set_page(priv, reg); | 449 | ret = set_page(priv, reg); |
450 | if (ret < 0) | ||
451 | return; | ||
439 | 452 | ||
440 | ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); | 453 | ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); |
441 | if (ret < 0) | 454 | if (ret < 0) |
@@ -449,7 +462,9 @@ reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val) | |||
449 | uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; | 462 | uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; |
450 | int ret; | 463 | int ret; |
451 | 464 | ||
452 | set_page(priv, reg); | 465 | ret = set_page(priv, reg); |
466 | if (ret < 0) | ||
467 | return; | ||
453 | 468 | ||
454 | ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); | 469 | ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); |
455 | if (ret < 0) | 470 | if (ret < 0) |
@@ -459,13 +474,21 @@ reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val) | |||
459 | static void | 474 | static void |
460 | reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val) | 475 | reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val) |
461 | { | 476 | { |
462 | reg_write(priv, reg, reg_read(priv, reg) | val); | 477 | int old_val; |
478 | |||
479 | old_val = reg_read(priv, reg); | ||
480 | if (old_val >= 0) | ||
481 | reg_write(priv, reg, old_val | val); | ||
463 | } | 482 | } |
464 | 483 | ||
465 | static void | 484 | static void |
466 | reg_clear(struct tda998x_priv *priv, uint16_t reg, uint8_t val) | 485 | reg_clear(struct tda998x_priv *priv, uint16_t reg, uint8_t val) |
467 | { | 486 | { |
468 | reg_write(priv, reg, reg_read(priv, reg) & ~val); | 487 | int old_val; |
488 | |||
489 | old_val = reg_read(priv, reg); | ||
490 | if (old_val >= 0) | ||
491 | reg_write(priv, reg, old_val & ~val); | ||
469 | } | 492 | } |
470 | 493 | ||
471 | static void | 494 | static void |
@@ -978,8 +1001,10 @@ read_edid_block(struct drm_encoder *encoder, uint8_t *buf, int blk) | |||
978 | 1001 | ||
979 | /* wait for block read to complete: */ | 1002 | /* wait for block read to complete: */ |
980 | for (i = 100; i > 0; i--) { | 1003 | for (i = 100; i > 0; i--) { |
981 | uint8_t val = reg_read(priv, REG_INT_FLAGS_2); | 1004 | ret = reg_read(priv, REG_INT_FLAGS_2); |
982 | if (val & INT_FLAGS_2_EDID_BLK_RD) | 1005 | if (ret < 0) |
1006 | return ret; | ||
1007 | if (ret & INT_FLAGS_2_EDID_BLK_RD) | ||
983 | break; | 1008 | break; |
984 | msleep(1); | 1009 | msleep(1); |
985 | } | 1010 | } |
@@ -1144,6 +1169,7 @@ tda998x_encoder_init(struct i2c_client *client, | |||
1144 | struct drm_encoder_slave *encoder_slave) | 1169 | struct drm_encoder_slave *encoder_slave) |
1145 | { | 1170 | { |
1146 | struct tda998x_priv *priv; | 1171 | struct tda998x_priv *priv; |
1172 | int ret; | ||
1147 | 1173 | ||
1148 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1174 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1149 | if (!priv) | 1175 | if (!priv) |
@@ -1172,8 +1198,11 @@ tda998x_encoder_init(struct i2c_client *client, | |||
1172 | tda998x_reset(priv); | 1198 | tda998x_reset(priv); |
1173 | 1199 | ||
1174 | /* read version: */ | 1200 | /* read version: */ |
1175 | priv->rev = reg_read(priv, REG_VERSION_LSB) | | 1201 | ret = reg_read(priv, REG_VERSION_LSB) | |
1176 | reg_read(priv, REG_VERSION_MSB) << 8; | 1202 | (reg_read(priv, REG_VERSION_MSB) << 8); |
1203 | if (ret < 0) | ||
1204 | goto fail; | ||
1205 | priv->rev = ret; | ||
1177 | 1206 | ||
1178 | /* mask off feature bits: */ | 1207 | /* mask off feature bits: */ |
1179 | priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */ | 1208 | priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */ |