diff options
-rw-r--r-- | drivers/gpu/drm/i2c/adv7511.c | 96 |
1 files changed, 46 insertions, 50 deletions
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index 840895a77825..828b60185016 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c | |||
@@ -33,6 +33,7 @@ struct adv7511 { | |||
33 | 33 | ||
34 | unsigned int current_edid_segment; | 34 | unsigned int current_edid_segment; |
35 | uint8_t edid_buf[256]; | 35 | uint8_t edid_buf[256]; |
36 | bool edid_read; | ||
36 | 37 | ||
37 | wait_queue_head_t wq; | 38 | wait_queue_head_t wq; |
38 | struct drm_encoder *encoder; | 39 | struct drm_encoder *encoder; |
@@ -379,69 +380,71 @@ static bool adv7511_hpd(struct adv7511 *adv7511) | |||
379 | return false; | 380 | return false; |
380 | } | 381 | } |
381 | 382 | ||
382 | static irqreturn_t adv7511_irq_handler(int irq, void *devid) | 383 | static int adv7511_irq_process(struct adv7511 *adv7511) |
383 | { | ||
384 | struct adv7511 *adv7511 = devid; | ||
385 | |||
386 | if (adv7511_hpd(adv7511)) | ||
387 | drm_helper_hpd_irq_event(adv7511->encoder->dev); | ||
388 | |||
389 | wake_up_all(&adv7511->wq); | ||
390 | |||
391 | return IRQ_HANDLED; | ||
392 | } | ||
393 | |||
394 | static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511, | ||
395 | unsigned int irq) | ||
396 | { | 384 | { |
397 | unsigned int irq0, irq1; | 385 | unsigned int irq0, irq1; |
398 | unsigned int pending; | ||
399 | int ret; | 386 | int ret; |
400 | 387 | ||
401 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); | 388 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); |
402 | if (ret < 0) | 389 | if (ret < 0) |
403 | return 0; | 390 | return ret; |
391 | |||
404 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); | 392 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); |
405 | if (ret < 0) | 393 | if (ret < 0) |
406 | return 0; | 394 | return ret; |
395 | |||
396 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); | ||
397 | regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); | ||
398 | |||
399 | if (irq0 & ADV7511_INT0_HDP) | ||
400 | drm_helper_hpd_irq_event(adv7511->encoder->dev); | ||
401 | |||
402 | if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { | ||
403 | adv7511->edid_read = true; | ||
407 | 404 | ||
408 | pending = (irq1 << 8) | irq0; | 405 | if (adv7511->i2c_main->irq) |
406 | wake_up_all(&adv7511->wq); | ||
407 | } | ||
409 | 408 | ||
410 | return pending & irq; | 409 | return 0; |
411 | } | 410 | } |
412 | 411 | ||
413 | static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq, | 412 | static irqreturn_t adv7511_irq_handler(int irq, void *devid) |
414 | int timeout) | 413 | { |
414 | struct adv7511 *adv7511 = devid; | ||
415 | int ret; | ||
416 | |||
417 | ret = adv7511_irq_process(adv7511); | ||
418 | return ret < 0 ? IRQ_NONE : IRQ_HANDLED; | ||
419 | } | ||
420 | |||
421 | /* ----------------------------------------------------------------------------- | ||
422 | * EDID retrieval | ||
423 | */ | ||
424 | |||
425 | static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout) | ||
415 | { | 426 | { |
416 | unsigned int pending; | ||
417 | int ret; | 427 | int ret; |
418 | 428 | ||
419 | if (adv7511->i2c_main->irq) { | 429 | if (adv7511->i2c_main->irq) { |
420 | ret = wait_event_interruptible_timeout(adv7511->wq, | 430 | ret = wait_event_interruptible_timeout(adv7511->wq, |
421 | adv7511_is_interrupt_pending(adv7511, irq), | 431 | adv7511->edid_read, msecs_to_jiffies(timeout)); |
422 | msecs_to_jiffies(timeout)); | ||
423 | if (ret <= 0) | ||
424 | return 0; | ||
425 | pending = adv7511_is_interrupt_pending(adv7511, irq); | ||
426 | } else { | 432 | } else { |
427 | if (timeout < 25) | 433 | for (; timeout > 0; timeout -= 25) { |
428 | timeout = 25; | 434 | ret = adv7511_irq_process(adv7511); |
429 | do { | 435 | if (ret < 0) |
430 | pending = adv7511_is_interrupt_pending(adv7511, irq); | 436 | break; |
431 | if (pending) | 437 | |
438 | if (adv7511->edid_read) | ||
432 | break; | 439 | break; |
440 | |||
433 | msleep(25); | 441 | msleep(25); |
434 | timeout -= 25; | 442 | } |
435 | } while (timeout >= 25); | ||
436 | } | 443 | } |
437 | 444 | ||
438 | return pending; | 445 | return adv7511->edid_read ? 0 : -EIO; |
439 | } | 446 | } |
440 | 447 | ||
441 | /* ----------------------------------------------------------------------------- | ||
442 | * EDID retrieval | ||
443 | */ | ||
444 | |||
445 | static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, | 448 | static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, |
446 | size_t len) | 449 | size_t len) |
447 | { | 450 | { |
@@ -463,21 +466,14 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, | |||
463 | return ret; | 466 | return ret; |
464 | 467 | ||
465 | if (status != 2) { | 468 | if (status != 2) { |
469 | adv7511->edid_read = false; | ||
466 | regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, | 470 | regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, |
467 | block); | 471 | block); |
468 | ret = adv7511_wait_for_interrupt(adv7511, | 472 | ret = adv7511_wait_for_edid(adv7511, 200); |
469 | ADV7511_INT0_EDID_READY | | 473 | if (ret < 0) |
470 | (ADV7511_INT1_DDC_ERROR << 8), 200); | 474 | return ret; |
471 | |||
472 | if (!(ret & ADV7511_INT0_EDID_READY)) | ||
473 | return -EIO; | ||
474 | } | 475 | } |
475 | 476 | ||
476 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), | ||
477 | ADV7511_INT0_EDID_READY); | ||
478 | regmap_write(adv7511->regmap, ADV7511_REG_INT(1), | ||
479 | ADV7511_INT1_DDC_ERROR); | ||
480 | |||
481 | /* Break this apart, hopefully more I2C controllers will | 477 | /* Break this apart, hopefully more I2C controllers will |
482 | * support 64 byte transfers than 256 byte transfers | 478 | * support 64 byte transfers than 256 byte transfers |
483 | */ | 479 | */ |