aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2015-03-02 07:38:52 -0500
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2015-03-19 06:28:55 -0400
commitc6169e49bd37c9556efd7564bcbbf7067cd7efa8 (patch)
tree4b5b52f3e2582d91a3863056a6f3903f17e7f1e7
parenta5241289c4139f0521b89e34a70f5f998463ae15 (diff)
drm: adv7511: Refactor power management
Remove the internal dependency on DPMS mode for power management by using a by a powered state boolean instead, and use the new power off handler at probe time. This ensure that the regmap cache is properly marked as dirty when the device is probed, and the registers properly synced during the first power up. As a side effect this removes the initialization of current_edid_segment at probe time, as the field will be initialized when the device is powered on, at the latest right before reading EDID data. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Christian Kohn <christian.kohn@xilinx.com> Tested-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Lars-Peter Clausen <lars@metafoo.de>
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c101
1 files changed, 53 insertions, 48 deletions
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index 828b60185016..b728523e194f 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -27,7 +27,7 @@ struct adv7511 {
27 struct regmap *regmap; 27 struct regmap *regmap;
28 struct regmap *packet_memory_regmap; 28 struct regmap *packet_memory_regmap;
29 enum drm_connector_status status; 29 enum drm_connector_status status;
30 int dpms_mode; 30 bool powered;
31 31
32 unsigned int f_tmds; 32 unsigned int f_tmds;
33 33
@@ -358,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511,
358 adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; 358 adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
359} 359}
360 360
361static void adv7511_power_on(struct adv7511 *adv7511)
362{
363 adv7511->current_edid_segment = -1;
364
365 regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
366 ADV7511_INT0_EDID_READY);
367 regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
368 ADV7511_INT1_DDC_ERROR);
369 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
370 ADV7511_POWER_POWER_DOWN, 0);
371
372 /*
373 * Per spec it is allowed to pulse the HDP signal to indicate that the
374 * EDID information has changed. Some monitors do this when they wakeup
375 * from standby or are enabled. When the HDP goes low the adv7511 is
376 * reset and the outputs are disabled which might cause the monitor to
377 * go to standby again. To avoid this we ignore the HDP pin for the
378 * first few seconds after enabling the output.
379 */
380 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
381 ADV7511_REG_POWER2_HDP_SRC_MASK,
382 ADV7511_REG_POWER2_HDP_SRC_NONE);
383
384 /*
385 * Most of the registers are reset during power down or when HPD is low.
386 */
387 regcache_sync(adv7511->regmap);
388
389 adv7511->powered = true;
390}
391
392static void adv7511_power_off(struct adv7511 *adv7511)
393{
394 /* TODO: setup additional power down modes */
395 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
396 ADV7511_POWER_POWER_DOWN,
397 ADV7511_POWER_POWER_DOWN);
398 regcache_mark_dirty(adv7511->regmap);
399
400 adv7511->powered = false;
401}
402
361/* ----------------------------------------------------------------------------- 403/* -----------------------------------------------------------------------------
362 * Interrupt and hotplug detection 404 * Interrupt and hotplug detection
363 */ 405 */
@@ -524,7 +566,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
524 unsigned int count; 566 unsigned int count;
525 567
526 /* Reading the EDID only works if the device is powered */ 568 /* Reading the EDID only works if the device is powered */
527 if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) { 569 if (!adv7511->powered) {
528 regmap_write(adv7511->regmap, ADV7511_REG_INT(0), 570 regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
529 ADV7511_INT0_EDID_READY); 571 ADV7511_INT0_EDID_READY);
530 regmap_write(adv7511->regmap, ADV7511_REG_INT(1), 572 regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
@@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
536 578
537 edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); 579 edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511);
538 580
539 if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) 581 if (!adv7511->powered)
540 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, 582 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
541 ADV7511_POWER_POWER_DOWN, 583 ADV7511_POWER_POWER_DOWN,
542 ADV7511_POWER_POWER_DOWN); 584 ADV7511_POWER_POWER_DOWN);
@@ -558,43 +600,10 @@ static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode)
558{ 600{
559 struct adv7511 *adv7511 = encoder_to_adv7511(encoder); 601 struct adv7511 *adv7511 = encoder_to_adv7511(encoder);
560 602
561 switch (mode) { 603 if (mode == DRM_MODE_DPMS_ON)
562 case DRM_MODE_DPMS_ON: 604 adv7511_power_on(adv7511);
563 adv7511->current_edid_segment = -1; 605 else
564 606 adv7511_power_off(adv7511);
565 regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
566 ADV7511_INT0_EDID_READY);
567 regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
568 ADV7511_INT1_DDC_ERROR);
569 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
570 ADV7511_POWER_POWER_DOWN, 0);
571 /*
572 * Per spec it is allowed to pulse the HDP signal to indicate
573 * that the EDID information has changed. Some monitors do this
574 * when they wakeup from standby or are enabled. When the HDP
575 * goes low the adv7511 is reset and the outputs are disabled
576 * which might cause the monitor to go to standby again. To
577 * avoid this we ignore the HDP pin for the first few seconds
578 * after enabling the output.
579 */
580 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
581 ADV7511_REG_POWER2_HDP_SRC_MASK,
582 ADV7511_REG_POWER2_HDP_SRC_NONE);
583 /* Most of the registers are reset during power down or
584 * when HPD is low
585 */
586 regcache_sync(adv7511->regmap);
587 break;
588 default:
589 /* TODO: setup additional power down modes */
590 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
591 ADV7511_POWER_POWER_DOWN,
592 ADV7511_POWER_POWER_DOWN);
593 regcache_mark_dirty(adv7511->regmap);
594 break;
595 }
596
597 adv7511->dpms_mode = mode;
598} 607}
599 608
600static enum drm_connector_status 609static enum drm_connector_status
@@ -622,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
622 * there is a pending HPD interrupt and the cable is connected there was 631 * there is a pending HPD interrupt and the cable is connected there was
623 * at least one transition from disconnected to connected and the chip 632 * at least one transition from disconnected to connected and the chip
624 * has to be reinitialized. */ 633 * has to be reinitialized. */
625 if (status == connector_status_connected && hpd && 634 if (status == connector_status_connected && hpd && adv7511->powered) {
626 adv7511->dpms_mode == DRM_MODE_DPMS_ON) {
627 regcache_mark_dirty(adv7511->regmap); 635 regcache_mark_dirty(adv7511->regmap);
628 adv7511_encoder_dpms(encoder, adv7511->dpms_mode); 636 adv7511_power_on(adv7511);
629 adv7511_get_modes(encoder, connector); 637 adv7511_get_modes(encoder, connector);
630 if (adv7511->status == connector_status_connected) 638 if (adv7511->status == connector_status_connected)
631 status = connector_status_disconnected; 639 status = connector_status_disconnected;
@@ -860,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
860 if (!adv7511) 868 if (!adv7511)
861 return -ENOMEM; 869 return -ENOMEM;
862 870
863 adv7511->dpms_mode = DRM_MODE_DPMS_OFF; 871 adv7511->powered = false;
864 adv7511->status = connector_status_disconnected; 872 adv7511->status = connector_status_disconnected;
865 873
866 ret = adv7511_parse_dt(dev->of_node, &link_config); 874 ret = adv7511_parse_dt(dev->of_node, &link_config);
@@ -920,10 +928,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
920 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 928 regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,
921 ADV7511_CEC_CTRL_POWER_DOWN); 929 ADV7511_CEC_CTRL_POWER_DOWN);
922 930
923 regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, 931 adv7511_power_off(adv7511);
924 ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN);
925
926 adv7511->current_edid_segment = -1;
927 932
928 i2c_set_clientdata(i2c, adv7511); 933 i2c_set_clientdata(i2c, adv7511);
929 934