|
@@ -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);
|
|
|
|