diff options
-rw-r--r-- | drivers/gpu/drm/i2c/adv7511.c | 101 |
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 { struct regmap *regmap; struct regmap *packet_memory_regmap; enum drm_connector_status status; - int dpms_mode; + bool powered; unsigned int f_tmds; @@ -358,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; } +static void adv7511_power_on(struct adv7511 *adv7511) +{ + adv7511->current_edid_segment = -1; + + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY); + regmap_write(adv7511->regmap, ADV7511_REG_INT(1), + ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); + + /* + * Per spec it is allowed to pulse the HDP signal to indicate that the + * EDID information has changed. Some monitors do this when they wakeup + * from standby or are enabled. When the HDP goes low the adv7511 is + * reset and the outputs are disabled which might cause the monitor to + * go to standby again. To avoid this we ignore the HDP pin for the + * first few seconds after enabling the output. + */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HDP_SRC_MASK, + ADV7511_REG_POWER2_HDP_SRC_NONE); + + /* + * Most of the registers are reset during power down or when HPD is low. + */ + regcache_sync(adv7511->regmap); + + adv7511->powered = true; +} + +static void adv7511_power_off(struct adv7511 *adv7511) +{ + /* TODO: setup additional power down modes */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, + ADV7511_POWER_POWER_DOWN); + regcache_mark_dirty(adv7511->regmap); + + adv7511->powered = false; +} + /* ----------------------------------------------------------------------------- * Interrupt and hotplug detection */ @@ -524,7 +566,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder, unsigned int count; /* Reading the EDID only works if the device is powered */ - if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) { + if (!adv7511->powered) { regmap_write(adv7511->regmap, ADV7511_REG_INT(0), ADV7511_INT0_EDID_READY); regmap_write(adv7511->regmap, ADV7511_REG_INT(1), @@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder, edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); - if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) + if (!adv7511->powered) regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); @@ -558,43 +600,10 @@ static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode) { struct adv7511 *adv7511 = encoder_to_adv7511(encoder); - switch (mode) { - case DRM_MODE_DPMS_ON: - adv7511->current_edid_segment = -1; - - regmap_write(adv7511->regmap, ADV7511_REG_INT(0), - ADV7511_INT0_EDID_READY); - regmap_write(adv7511->regmap, ADV7511_REG_INT(1), - ADV7511_INT1_DDC_ERROR); - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, 0); - /* - * Per spec it is allowed to pulse the HDP signal to indicate - * that the EDID information has changed. Some monitors do this - * when they wakeup from standby or are enabled. When the HDP - * goes low the adv7511 is reset and the outputs are disabled - * which might cause the monitor to go to standby again. To - * avoid this we ignore the HDP pin for the first few seconds - * after enabling the output. - */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HDP_SRC_MASK, - ADV7511_REG_POWER2_HDP_SRC_NONE); - /* Most of the registers are reset during power down or - * when HPD is low - */ - regcache_sync(adv7511->regmap); - break; - default: - /* TODO: setup additional power down modes */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, - ADV7511_POWER_POWER_DOWN); - regcache_mark_dirty(adv7511->regmap); - break; - } - - adv7511->dpms_mode = mode; + if (mode == DRM_MODE_DPMS_ON) + adv7511_power_on(adv7511); + else + adv7511_power_off(adv7511); } static enum drm_connector_status @@ -622,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder, * there is a pending HPD interrupt and the cable is connected there was * at least one transition from disconnected to connected and the chip * has to be reinitialized. */ - if (status == connector_status_connected && hpd && - adv7511->dpms_mode == DRM_MODE_DPMS_ON) { + if (status == connector_status_connected && hpd && adv7511->powered) { regcache_mark_dirty(adv7511->regmap); - adv7511_encoder_dpms(encoder, adv7511->dpms_mode); + adv7511_power_on(adv7511); adv7511_get_modes(encoder, connector); if (adv7511->status == connector_status_connected) status = connector_status_disconnected; @@ -860,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) if (!adv7511) return -ENOMEM; - adv7511->dpms_mode = DRM_MODE_DPMS_OFF; + adv7511->powered = false; adv7511->status = connector_status_disconnected; 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) regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, ADV7511_CEC_CTRL_POWER_DOWN); - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, - ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); - - adv7511->current_edid_segment = -1; + adv7511_power_off(adv7511); i2c_set_clientdata(i2c, adv7511); |