diff mbox

[2/5] drm/i2c: adv7511: Initial support for adv7533

Message ID 1437977819-24199-3-git-send-email-architt@codeaurora.org
State New, archived
Headers show

Commit Message

Archit Taneja July 27, 2015, 6:16 a.m. UTC
From: Lars-Peter Clausen <lars@metafoo.de>

ADV7533 is a DSI to HDMI encoder chip. It is a derivative of ADV7511,
with additional blocks to translate input DSI data to parallel RGB
data. Besides the ADV7511 i2c register map, it has additional registers
that require to be configured to activate the DSI blocks.

Use DT compatible strings to populate the adv7533 type enum. Add minimal
register configurations belonging to the DSI/CEC register map.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/i2c/adv7511.c | 155 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 131 insertions(+), 24 deletions(-)

Comments

Bjorn Andersson July 28, 2015, 3:27 a.m. UTC | #1
On Sun 26 Jul 23:16 PDT 2015, Archit Taneja wrote:

> From: Lars-Peter Clausen <lars@metafoo.de>
> 
[..]
> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c

[..]

>  
> +static const struct of_device_id adv7511_of_ids[] = {
> +	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
> +	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
> +	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
> +	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, adv7511_of_ids);

Please leave this at the bottom.

> +
>  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
>  {
>  	struct adv7511_link_config link_config;
> @@ -871,9 +938,22 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
>  	adv7511->powered = false;
>  	adv7511->status = connector_status_disconnected;
>  
> -	ret = adv7511_parse_dt(dev->of_node, &link_config);
> -	if (ret)
> -		return ret;
> +	if (dev->of_node) {
> +		const struct of_device_id *of_id;
> +
> +		of_id = of_match_node(adv7511_of_ids, dev->of_node);

If you use of_device_get_match_data() instead you don't need to move the
of_device_id table.

> +		adv7511->type = (enum adv7511_type) of_id->data;
> +	} else {
> +		adv7511->type = id->driver_data;
> +	}
> +
[..]

>  
>  static const struct i2c_device_id adv7511_i2c_ids[] = {
> -	{ "adv7511", 0 },
> -	{ "adv7511w", 0 },
> -	{ "adv7513", 0 },
> +	{ "adv7511", ADV7511 },
> +	{ "adv7511w", ADV7511 },
> +	{ "adv7513", ADV7511 },
> +	{ "adv7533", ADV7533 },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
>  
> -static const struct of_device_id adv7511_of_ids[] = {
> -	{ .compatible = "adi,adv7511", },
> -	{ .compatible = "adi,adv7511w", },
> -	{ .compatible = "adi,adv7513", },
> -	{ }
> -};
> -MODULE_DEVICE_TABLE(of, adv7511_of_ids);
> -

Regards,
Bjorn
Archit Taneja Aug. 3, 2015, 5:39 a.m. UTC | #2
On 07/28/2015 08:57 AM, Bjorn Andersson wrote:
> On Sun 26 Jul 23:16 PDT 2015, Archit Taneja wrote:
>
>> From: Lars-Peter Clausen <lars@metafoo.de>
>>
> [..]
>> diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
>
> [..]
>
>>
>> +static const struct of_device_id adv7511_of_ids[] = {
>> +	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
>> +	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
>> +	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
>> +	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, adv7511_of_ids);
>
> Please leave this at the bottom.
>
>> +
>>   static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
>>   {
>>   	struct adv7511_link_config link_config;
>> @@ -871,9 +938,22 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
>>   	adv7511->powered = false;
>>   	adv7511->status = connector_status_disconnected;
>>
>> -	ret = adv7511_parse_dt(dev->of_node, &link_config);
>> -	if (ret)
>> -		return ret;
>> +	if (dev->of_node) {
>> +		const struct of_device_id *of_id;
>> +
>> +		of_id = of_match_node(adv7511_of_ids, dev->of_node);
>
> If you use of_device_get_match_data() instead you don't need to move the
> of_device_id table.

Thanks, will use this in future revisions.

Archit
diff mbox

Patch

diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index cf5bb29..63a3d20 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -20,12 +20,18 @@ 
 
 #include "adv7511.h"
 
+enum adv7511_type {
+	ADV7511,
+	ADV7533,
+};
+
 struct adv7511 {
 	struct i2c_client *i2c_main;
 	struct i2c_client *i2c_edid;
+	struct i2c_client *i2c_cec;
 
 	struct regmap *regmap;
-	struct regmap *packet_memory_regmap;
+	struct regmap *regmap_cec;
 	enum drm_connector_status status;
 	bool powered;
 
@@ -46,6 +52,8 @@  struct adv7511 {
 	struct edid *edid;
 
 	struct gpio_desc *gpio_pd;
+
+	enum adv7511_type type;
 };
 
 static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
@@ -66,6 +74,23 @@  static const struct reg_default adv7511_fixed_registers[] = {
 	{ 0x55, 0x02 },
 };
 
+/* ADI recommended values for proper operation. */
+static const struct reg_default adv7533_fixed_registers[] = {
+	{ 0x16, 0x20 },
+	{ 0x9a, 0xe0 },
+	{ 0xba, 0x70 },
+	{ 0xde, 0x82 },
+	{ 0xe4, 0x40 },
+	{ 0xe5, 0x80 },
+};
+
+static const struct reg_default adv7533_cec_fixed_registers[] = {
+	{ 0x15, 0xd0 },
+	{ 0x17, 0xd0 },
+	{ 0x24, 0x20 },
+	{ 0x57, 0x11 },
+};
+
 /* -----------------------------------------------------------------------------
  * Register access
  */
@@ -158,6 +183,15 @@  static const struct regmap_config adv7511_regmap_config = {
 	.volatile_reg = adv7511_register_volatile,
 };
 
+static const struct regmap_config adv7533_cec_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+
 /* -----------------------------------------------------------------------------
  * Hardware configuration
  */
@@ -358,6 +392,25 @@  static void adv7511_set_link_config(struct adv7511 *adv7511,
 	adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
 }
 
+static void adv7511_dsi_receiver_dpms(struct adv7511 *adv7511)
+{
+	if (adv7511->type != ADV7533)
+		return;
+
+	if (adv7511->powered) {
+		/* set number of dsi lanes (hardcoded to 4 for now) */
+		regmap_write(adv7511->regmap_cec, 0x1c, 0x4 << 4);
+		/* disable internal timing generator */
+		regmap_write(adv7511->regmap_cec, 0x27, 0x0b);
+		/* enable hdmi */
+		regmap_write(adv7511->regmap_cec, 0x03, 0x89);
+		/* disable test mode */
+		regmap_write(adv7511->regmap_cec, 0x55, 0x00);
+	} else {
+		regmap_write(adv7511->regmap_cec, 0x03, 0x0b);
+	}
+}
+
 static void adv7511_power_on(struct adv7511 *adv7511)
 {
 	adv7511->current_edid_segment = -1;
@@ -387,6 +440,8 @@  static void adv7511_power_on(struct adv7511 *adv7511)
 	regcache_sync(adv7511->regmap);
 
 	adv7511->powered = true;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 static void adv7511_power_off(struct adv7511 *adv7511)
@@ -398,6 +453,8 @@  static void adv7511_power_off(struct adv7511 *adv7511)
 	regcache_mark_dirty(adv7511->regmap);
 
 	adv7511->powered = false;
+
+	adv7511_dsi_receiver_dpms(adv7511);
 }
 
 /* -----------------------------------------------------------------------------
@@ -567,6 +624,9 @@  static int adv7511_get_modes(struct drm_encoder *encoder,
 
 	/* Reading the EDID only works if the device is powered */
 	if (!adv7511->powered) {
+		regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
+				   ADV7511_REG_POWER2_HDP_SRC_MASK,
+				   ADV7511_REG_POWER2_HDP_SRC_NONE);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
 			     ADV7511_INT0_EDID_READY);
 		regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
@@ -770,8 +830,6 @@  static int adv7511_parse_dt(struct device_node *np,
 	const char *str;
 	int ret;
 
-	memset(config, 0, sizeof(*config));
-
 	of_property_read_u32(np, "adi,input-depth", &config->input_color_depth);
 	if (config->input_color_depth != 8 && config->input_color_depth != 10 &&
 	    config->input_color_depth != 12)
@@ -853,6 +911,15 @@  static const int edid_i2c_addr = 0x7e;
 static const int packet_i2c_addr = 0x70;
 static const int cec_i2c_addr = 0x78;
 
+static const struct of_device_id adv7511_of_ids[] = {
+	{ .compatible = "adi,adv7511", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7511w", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7513", .data = (void *) ADV7511 },
+	{ .compatible = "adi,adv7533", .data = (void *) ADV7533 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adv7511_of_ids);
+
 static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
 	struct adv7511_link_config link_config;
@@ -871,9 +938,22 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	adv7511->powered = false;
 	adv7511->status = connector_status_disconnected;
 
-	ret = adv7511_parse_dt(dev->of_node, &link_config);
-	if (ret)
-		return ret;
+	if (dev->of_node) {
+		const struct of_device_id *of_id;
+
+		of_id = of_match_node(adv7511_of_ids, dev->of_node);
+		adv7511->type = (enum adv7511_type) of_id->data;
+	} else {
+		adv7511->type = id->driver_data;
+	}
+
+	memset(&link_config, 0, sizeof(link_config));
+
+	if (adv7511->type == ADV7511) {
+		ret = adv7511_parse_dt(dev->of_node, &link_config);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * The power down GPIO is optional. If present, toggle it from active to
@@ -897,10 +977,19 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 		return ret;
 	dev_dbg(dev, "Rev. %d\n", val);
 
-	ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
-				    ARRAY_SIZE(adv7511_fixed_registers));
-	if (ret)
-		return ret;
+	if (adv7511->type == ADV7511) {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7511_fixed_registers,
+				ARRAY_SIZE(adv7511_fixed_registers));
+		if (ret)
+			return ret;
+	} else {
+		ret = regmap_register_patch(adv7511->regmap,
+				adv7533_fixed_registers,
+				ARRAY_SIZE(adv7533_fixed_registers));
+		if (ret)
+			return ret;
+	}
 
 	regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
 	regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
@@ -913,6 +1002,27 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 	if (!adv7511->i2c_edid)
 		return -ENOMEM;
 
+	adv7511->i2c_cec = i2c_new_dummy(i2c->adapter, cec_i2c_addr >> 1);
+	if (!adv7511->i2c_cec) {
+		ret = -ENOMEM;
+		goto err_i2c_unregister_edid;
+	}
+
+	adv7511->regmap_cec = devm_regmap_init_i2c(adv7511->i2c_cec,
+					&adv7533_cec_regmap_config);
+	if (IS_ERR(adv7511->regmap_cec)) {
+		ret = PTR_ERR(adv7511->regmap_cec);
+		goto err_i2c_unregister_cec;
+	}
+
+	if (adv7511->type == ADV7533) {
+		ret = regmap_register_patch(adv7511->regmap_cec,
+				adv7533_cec_fixed_registers,
+				ARRAY_SIZE(adv7533_cec_fixed_registers));
+		if (ret)
+			return ret;
+	}
+
 	if (i2c->irq) {
 		init_waitqueue_head(&adv7511->wq);
 
@@ -921,7 +1031,7 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 						IRQF_ONESHOT, dev_name(dev),
 						adv7511);
 		if (ret)
-			goto err_i2c_unregister_device;
+			goto err_i2c_unregister_cec;
 	}
 
 	/* CEC is unused for now */
@@ -932,11 +1042,14 @@  static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
 	i2c_set_clientdata(i2c, adv7511);
 
-	adv7511_set_link_config(adv7511, &link_config);
+	if (adv7511->type == ADV7511)
+		adv7511_set_link_config(adv7511, &link_config);
 
 	return 0;
 
-err_i2c_unregister_device:
+err_i2c_unregister_cec:
+	i2c_unregister_device(adv7511->i2c_cec);
+err_i2c_unregister_edid:
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	return ret;
@@ -946,6 +1059,7 @@  static int adv7511_remove(struct i2c_client *i2c)
 {
 	struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
+	i2c_unregister_device(adv7511->i2c_cec);
 	i2c_unregister_device(adv7511->i2c_edid);
 
 	kfree(adv7511->edid);
@@ -968,21 +1082,14 @@  static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
 }
 
 static const struct i2c_device_id adv7511_i2c_ids[] = {
-	{ "adv7511", 0 },
-	{ "adv7511w", 0 },
-	{ "adv7513", 0 },
+	{ "adv7511", ADV7511 },
+	{ "adv7511w", ADV7511 },
+	{ "adv7513", ADV7511 },
+	{ "adv7533", ADV7533 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);
 
-static const struct of_device_id adv7511_of_ids[] = {
-	{ .compatible = "adi,adv7511", },
-	{ .compatible = "adi,adv7511w", },
-	{ .compatible = "adi,adv7513", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, adv7511_of_ids);
-
 static struct drm_i2c_encoder_driver adv7511_driver = {
 	.i2c_driver = {
 		.driver = {