diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index 40c4d4a5517b..be8d74ff632b 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/workqueue.h>
 
 #include <drm/drm_atomic_helper.h>
@@ -26,6 +27,7 @@ struct tfp410 {
 	u32			bus_format;
 	struct delayed_work	hpd_work;
 	struct gpio_desc	*powerdown;
+	struct regmap		*regmap;
 
 	struct drm_bridge_timings timings;
 	struct drm_bridge	*next_bridge;
@@ -213,7 +215,7 @@ static const struct drm_bridge_timings tfp410_default_timings = {
 	.hold_time_ps = 1300,
 };
 
-static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
+static int tfp410_parse_timings(struct tfp410 *dvi)
 {
 	struct drm_bridge_timings *timings = &dvi->timings;
 	struct device_node *ep;
@@ -224,7 +226,7 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
 	/* Start with defaults. */
 	*timings = tfp410_default_timings;
 
-	if (i2c)
+	if (dvi->regmap)
 		/*
 		 * In I2C mode timings are configured through the I2C interface.
 		 * As the driver doesn't support I2C configuration yet, we just
@@ -283,10 +285,10 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
 	return 0;
 }
 
-static int tfp410_init(struct device *dev, bool i2c)
+static int tfp410_init(struct tfp410 *dvi)
 {
 	struct device_node *node;
-	struct tfp410 *dvi;
+	struct device *dev = dvi->dev;
 	int ret;
 
 	if (!dev->of_node) {
@@ -294,11 +296,6 @@ static int tfp410_init(struct device *dev, bool i2c)
 		return -ENXIO;
 	}
 
-	dvi = devm_kzalloc(dev, sizeof(*dvi), GFP_KERNEL);
-	if (!dvi)
-		return -ENOMEM;
-
-	dvi->dev = dev;
 	dev_set_drvdata(dev, dvi);
 
 	dvi->bridge.funcs = &tfp410_bridge_funcs;
@@ -306,7 +303,7 @@ static int tfp410_init(struct device *dev, bool i2c)
 	dvi->bridge.timings = &dvi->timings;
 	dvi->bridge.type = DRM_MODE_CONNECTOR_DVID;
 
-	ret = tfp410_parse_timings(dvi, i2c);
+	ret = tfp410_parse_timings(dvi);
 	if (ret)
 		return ret;
 
@@ -346,7 +343,15 @@ static int tfp410_fini(struct device *dev)
 
 static int tfp410_probe(struct platform_device *pdev)
 {
-	return tfp410_init(&pdev->dev, false);
+	struct tfp410 *dvi;
+
+	dvi = devm_kzalloc(&pdev->dev, sizeof(*dvi), GFP_KERNEL);
+	if (!dvi)
+		return -ENOMEM;
+
+	dvi->dev = &pdev->dev;
+
+	return tfp410_init(dvi);
 }
 
 static int tfp410_remove(struct platform_device *pdev)
@@ -370,20 +375,111 @@ static struct platform_driver tfp410_platform_driver = {
 };
 
 #if IS_ENABLED(CONFIG_I2C)
-/* There is currently no i2c functionality. */
+
+#define TFP410_VEN_ID_LO		0x00
+#define TFP410_VEN_ID_HI		0x01
+#define TFP410_DEV_ID_LO		0x02
+#define TFP410_DEV_ID_HI		0x03
+#define TFP410_REV_ID			0x04
+#define TFP410_CTL_1_MODE		0x08
+#define TFP410_CTL_2_MODE		0x09
+#define TFP410_CTL_3_MODE		0x0a
+#define TFP410_CFG			0x0b
+#define TFP410_DE_DLY			0x32
+#define TFP410_DE_CTL			0x33
+#define TFP410_DE_TOP			0x34
+#define TFP410_DE_CNT_LO		0x36
+#define TFP410_DE_CNT_HI		0x37
+#define TFP410_DE_LIN_LO		0x38
+#define TFP410_DE_LIN_HI		0x39
+#define TFP410_H_RES_LO			0x3a
+#define TFP410_H_RES_HI			0x3b
+#define TFP410_V_RES_LO			0x3c
+#define TFP410_V_RES_HI			0x3d
+
+static const struct regmap_config tfp410_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0x3d,
+	.wr_table = &(const struct regmap_access_table) {
+		.yes_ranges = (const struct regmap_range[]) {
+			{
+				.range_min = TFP410_CTL_1_MODE,
+				.range_max = TFP410_DE_LIN_HI,
+			},
+		},
+		.n_yes_ranges = 1,
+	},
+};
+
+static int tfp410_check_version(struct tfp410 *dvi)
+{
+	unsigned int value;
+	u16 vendor_id;
+	u16 device_id;
+	u8 revision_id;
+	int ret;
+
+	ret = regmap_read(dvi->regmap, TFP410_VEN_ID_LO, &value);
+	if (ret < 0)
+		return ret;
+	vendor_id = value;
+
+	ret = regmap_read(dvi->regmap, TFP410_VEN_ID_HI, &value);
+	if (ret < 0)
+		return ret;
+	vendor_id |= value << 8;
+
+	ret = regmap_read(dvi->regmap, TFP410_DEV_ID_LO, &value);
+	if (ret < 0)
+		return ret;
+	device_id = value;
+
+	ret = regmap_read(dvi->regmap, TFP410_DEV_ID_HI, &value);
+	if (ret < 0)
+		return ret;
+	device_id |= value << 8;
+
+	ret = regmap_read(dvi->regmap, TFP410_REV_ID, &value);
+	if (ret < 0)
+		return ret;
+	revision_id = value;
+
+	if (vendor_id != 0x014c || device_id != 0x0410) {
+		dev_err(dvi->dev, "invalid device ID %04x:%04x\n",
+			vendor_id, device_id);
+		return -ENODEV;
+	}
+
+	dev_info(dvi->dev, "Found TFP410 revision 0x%02x\n", revision_id);
+
+	return 0;
+}
+
 static int tfp410_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
-	int reg;
+	struct tfp410 *dvi;
+	int ret;
 
-	if (!client->dev.of_node ||
-	    of_property_read_u32(client->dev.of_node, "reg", &reg)) {
-		dev_err(&client->dev,
-			"Can't get i2c reg property from device-tree\n");
-		return -ENXIO;
+	dvi = devm_kzalloc(&client->dev, sizeof(*dvi), GFP_KERNEL);
+	if (!dvi)
+		return -ENOMEM;
+
+	dvi->dev = &client->dev;
+
+	dvi->regmap = devm_regmap_init_i2c(client, &tfp410_regmap_config);
+	if (IS_ERR(dvi->regmap))
+		return PTR_ERR(dvi->regmap);
+
+	ret = tfp410_check_version(dvi);
+	if (ret < 0) {
+		dev_err(dvi->dev, "failed to read device ID (%d)\n", ret);
+		return ret;
 	}
 
-	return tfp410_init(&client->dev, true);
+	return tfp410_init(dvi);
 }
 
 static int tfp410_i2c_remove(struct i2c_client *client)
