drm/bridge: adv7533: Initial support for ADV7533
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 Rx block.
Create a new config that enables ADV7533 support. Use DT compatible
strings to populate the ADV7533 type enum. Add minimal register
configurations belonging to the DSI/CEC register map. Keep the ADV7533
code in a separate file.
Originally worked on by Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 1fff0ab..e33702b 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -8,48 +8,17 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/regmap.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include "adv7511.h"
-struct adv7511 {
- struct i2c_client *i2c_main;
- struct i2c_client *i2c_edid;
-
- struct regmap *regmap;
- struct regmap *packet_memory_regmap;
- enum drm_connector_status status;
- bool powered;
-
- unsigned int f_tmds;
-
- unsigned int current_edid_segment;
- uint8_t edid_buf[256];
- bool edid_read;
-
- wait_queue_head_t wq;
- struct drm_bridge bridge;
- struct drm_connector connector;
-
- bool embedded_sync;
- enum adv7511_sync_polarity vsync_polarity;
- enum adv7511_sync_polarity hsync_polarity;
- bool rgb;
-
- struct edid *edid;
-
- struct gpio_desc *gpio_pd;
-};
-
/* ADI recommended values for proper operation. */
static const struct reg_sequence adv7511_fixed_registers[] = {
{ 0x98, 0x03 },
@@ -391,6 +360,9 @@
*/
regcache_sync(adv7511->regmap);
+ if (adv7511->type == ADV7533)
+ adv7533_dsi_power_on(adv7511);
+
adv7511->powered = true;
}
@@ -402,6 +374,9 @@
ADV7511_POWER_POWER_DOWN);
regcache_mark_dirty(adv7511->regmap);
+ if (adv7511->type == ADV7533)
+ adv7533_dsi_power_off(adv7511);
+
adv7511->powered = false;
}
@@ -862,8 +837,6 @@
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)
@@ -963,9 +936,18 @@
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)
+ adv7511->type = (enum adv7511_type)of_device_get_match_data(dev);
+ 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
@@ -989,8 +971,12 @@
return ret;
dev_dbg(dev, "Rev. %d\n", val);
- ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers,
- ARRAY_SIZE(adv7511_fixed_registers));
+ if (adv7511->type == ADV7511)
+ ret = regmap_register_patch(adv7511->regmap,
+ adv7511_fixed_registers,
+ ARRAY_SIZE(adv7511_fixed_registers));
+ else
+ ret = adv7533_patch_registers(adv7511);
if (ret)
return ret;
@@ -1005,6 +991,12 @@
if (!adv7511->i2c_edid)
return -ENOMEM;
+ if (adv7511->type == ADV7533) {
+ ret = adv7533_init_cec(adv7511);
+ if (ret)
+ goto err_i2c_unregister_edid;
+ }
+
if (i2c->irq) {
init_waitqueue_head(&adv7511->wq);
@@ -1013,7 +1005,7 @@
IRQF_ONESHOT, dev_name(dev),
adv7511);
if (ret)
- goto err_i2c_unregister_device;
+ goto err_unregister_cec;
}
/* CEC is unused for now */
@@ -1024,7 +1016,8 @@
i2c_set_clientdata(i2c, adv7511);
- adv7511_set_link_config(adv7511, &link_config);
+ if (adv7511->type == ADV7511)
+ adv7511_set_link_config(adv7511, &link_config);
adv7511->bridge.funcs = &adv7511_bridge_funcs;
adv7511->bridge.of_node = dev->of_node;
@@ -1032,12 +1025,14 @@
ret = drm_bridge_add(&adv7511->bridge);
if (ret) {
dev_err(dev, "failed to add adv7511 bridge\n");
- goto err_i2c_unregister_device;
+ goto err_unregister_cec;
}
return 0;
-err_i2c_unregister_device:
+err_unregister_cec:
+ adv7533_uninit_cec(adv7511);
+err_i2c_unregister_edid:
i2c_unregister_device(adv7511->i2c_edid);
return ret;
@@ -1049,6 +1044,7 @@
drm_bridge_remove(&adv7511->bridge);
+ adv7533_uninit_cec(adv7511);
i2c_unregister_device(adv7511->i2c_edid);
kfree(adv7511->edid);
@@ -1057,17 +1053,23 @@
}
static const struct i2c_device_id adv7511_i2c_ids[] = {
- { "adv7511", 0 },
- { "adv7511w", 0 },
- { "adv7513", 0 },
+ { "adv7511", ADV7511 },
+ { "adv7511w", ADV7511 },
+ { "adv7513", ADV7511 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+ { "adv7533", ADV7533 },
+#endif
{ }
};
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", },
+ { .compatible = "adi,adv7511", .data = (void *)ADV7511 },
+ { .compatible = "adi,adv7511w", .data = (void *)ADV7511 },
+ { .compatible = "adi,adv7513", .data = (void *)ADV7511 },
+#ifdef CONFIG_DRM_I2C_ADV7533
+ { .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+#endif
{ }
};
MODULE_DEVICE_TABLE(of, adv7511_of_ids);