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 */ |
