aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c96
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
382static irqreturn_t adv7511_irq_handler(int irq, void *devid) 383static 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
394static 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
413static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq, 412static 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
425static 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
445static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, 448static 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 */