diff --git a/drivers/i2c/i2c-core-of-prober.c b/drivers/i2c/i2c-core-of-prober.c
index 56b06ad7aa64..04242ff86e69 100644
--- a/drivers/i2c/i2c-core-of-prober.c
+++ b/drivers/i2c/i2c-core-of-prober.c
@@ -5,16 +5,19 @@
  * Copyright (C) 2024 Google LLC
  */
 
+#include <linux/bitmap.h>
 #include <linux/cleanup.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dev_printk.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/types.h>
 
 /*
  * Some devices, such as Google Hana Chromebooks, are produced by multiple
@@ -29,12 +32,14 @@
  * address responds.
  *
  * TODO:
- * - Support handling common GPIOs.
+ * - Support inverted polarity GPIOs, such as electrical high to "disable".
+ *   Seen on some OmniVision camera sensors.
  * - Support I2C muxes
  */
 
 struct i2c_of_probe_data {
 	const struct i2c_of_probe_opts *opts;
+	struct gpio_descs *gpiods;
 	struct regulator_bulk_data *regulators;
 	unsigned int regulators_num;
 };
@@ -85,10 +90,90 @@ static void i2c_of_probe_free_regulators(struct i2c_of_probe_data *data)
 	regulator_bulk_free(data->regulators_num, data->regulators);
 	data->regulators_num = 0;
 	data->regulators = NULL;
+};
+
+/*
+ * Returns 1 if property is GPIO and GPIO successfully requested,
+ * 0 if not a GPIO property, or error if request for GPIO failed.
+ */
+static int i2c_of_probe_get_gpiod(struct device_node *node, struct property *prop,
+				  struct i2c_of_probe_data *data)
+{
+	struct fwnode_handle *fwnode = of_fwnode_handle(node);
+	struct gpio_descs *gpiods;
+	struct gpio_desc *gpiod;
+	char propname[32]; /* 32 is max size of property name */
+	char *con_id = NULL;
+	size_t new_size;
+	int len, ret;
+
+	len = gpio_get_property_name_length(prop->name);
+	if (len < 0)
+		return 0;
+
+	ret = strscpy(propname, prop->name);
+	if (ret < 0) {
+		pr_err("%pOF: length of GPIO name \"%s\" exceeds current limit\n",
+		       node, prop->name);
+		return -EINVAL;
+	}
+
+	if (len > 0) {
+		/* "len < ARRAY_SIZE(propname)" guaranteed by strscpy() above */
+		propname[len] = '\0';
+		con_id = propname;
+	}
+
+	/*
+	 * GPIO descriptors are not reference counted. GPIOD_FLAGS_BIT_NONEXCLUSIVE
+	 * can't differentiate between GPIOs shared between devices to be probed and
+	 * other devices (which is incorrect). If the initial request fails with
+	 * -EBUSY, retry with GPIOD_FLAGS_BIT_NONEXCLUSIVE and see if it matches
+	 * any existing ones.
+	 */
+	gpiod = fwnode_gpiod_get_index(fwnode, con_id, 0, GPIOD_ASIS, "i2c-of-prober");
+	if (IS_ERR(gpiod)) {
+		if (PTR_ERR(gpiod) != -EBUSY || !data->gpiods)
+			return PTR_ERR(gpiod);
+
+		gpiod = fwnode_gpiod_get_index(fwnode, con_id, 0,
+					       GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+					       "i2c-of-prober");
+		for (unsigned int i = 0; i < data->gpiods->ndescs; i++)
+			if (gpiod == data->gpiods->desc[i])
+				return 1;
+
+		return -EBUSY;
+	}
+
+	new_size = struct_size(gpiods, desc, data->gpiods ? data->gpiods->ndescs + 1 : 1);
+	gpiods = krealloc(data->gpiods, new_size, GFP_KERNEL);
+	if (!gpiods) {
+		gpiod_put(gpiod);
+		return -ENOMEM;
+	}
+
+	data->gpiods = gpiods;
+	data->gpiods->desc[data->gpiods->ndescs++] = gpiod;
+
+	return 1;
+}
+
+/*
+ * This is split into two functions because in the normal flow the GPIOs
+ * have to be released before the actual driver probes so that the latter
+ * can acquire them.
+ */
+static void i2c_of_probe_free_gpios(struct i2c_of_probe_data *data)
+{
+	if (data->gpiods)
+		gpiod_put_array(data->gpiods);
+	data->gpiods = NULL;
 }
 
 static void i2c_of_probe_free_res(struct i2c_of_probe_data *data)
 {
+	i2c_of_probe_free_gpios(data);
 	i2c_of_probe_free_regulators(data);
 }
 
@@ -104,6 +189,18 @@ static int i2c_of_probe_get_res(struct device *dev, struct device_node *node,
 		goto err_cleanup;
 	}
 
+	for_each_property_of_node(node, prop) {
+		dev_dbg(dev, "Trying property %pOF/%s\n", node, prop->name);
+
+		/* GPIOs */
+		ret = i2c_of_probe_get_gpiod(node, prop, data);
+		if (ret < 0) {
+			dev_err_probe(dev, ret, "Failed to get GPIO from %pOF/%s\n",
+				      node, prop->name);
+			goto err_cleanup;
+		}
+	}
+
 	return 0;
 
 err_cleanup:
@@ -131,6 +228,37 @@ static void i2c_of_probe_disable_regulators(struct i2c_of_probe_data *data)
 	regulator_bulk_disable(data->regulators_num, data->regulators);
 }
 
+static int i2c_of_probe_set_gpios(struct device *dev, struct i2c_of_probe_data *data)
+{
+	int ret;
+	int gpio_i;
+
+	if (!data->gpiods)
+		return 0;
+
+	for (gpio_i = 0; gpio_i < data->gpiods->ndescs; gpio_i++) {
+		/*
+		 * "reset" GPIOs normally have opposite polarity compared to
+		 * "enable" GPIOs. Instead of parsing the flags again, simply
+		 * set the raw value to high.
+		 */
+		dev_dbg(dev, "Setting GPIO %d\n", gpio_i);
+		ret = gpiod_direction_output_raw(data->gpiods->desc[gpio_i], 1);
+		if (ret)
+			goto disable_gpios;
+	}
+
+	msleep(data->opts->post_reset_deassert_delay_ms);
+
+	return 0;
+
+disable_gpios:
+	for (gpio_i--; gpio_i >= 0; gpio_i--)
+		gpiod_set_raw_value_cansleep(data->gpiods->desc[gpio_i], 0);
+
+	return ret;
+}
+
 static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data *data)
 {
 	int ret;
@@ -139,7 +267,15 @@ static int i2c_of_probe_enable_res(struct device *dev, struct i2c_of_probe_data
 	if (ret)
 		return ret;
 
+	ret = i2c_of_probe_set_gpios(dev, data);
+	if (ret)
+		goto err_disable_regulators;
+
 	return 0;
+
+err_disable_regulators:
+	i2c_of_probe_disable_regulators(data);
+	return ret;
 }
 
 static struct device_node *i2c_of_probe_get_i2c_node(struct device *dev, const char *type)
@@ -191,6 +327,8 @@ static int i2c_of_probe_enable_node(struct device *dev, struct device_node *node
 static const struct i2c_of_probe_opts i2c_of_probe_opts_default = {
 	/* largest post-power-on pre-reset-deassert delay seen among drivers */
 	.post_power_on_delay_ms = 500,
+	/* largest post-reset-deassert delay seen in tree for Elan I2C HID */
+	.post_reset_deassert_delay_ms = 300,
 };
 
 /**
@@ -264,6 +402,8 @@ int i2c_of_probe_component(struct device *dev, const char *type, const struct i2
 	}
 
 	dev_dbg(dev, "Resources: # of regulator supplies = %d\n", probe_data.regulators_num);
+	dev_dbg(dev, "Resources: # of GPIOs = %d\n",
+		probe_data.gpiods ? probe_data.gpiods->ndescs : 0);
 
 	/* Enable resources */
 	ret = i2c_of_probe_enable_res(dev, &probe_data);
@@ -283,6 +423,7 @@ int i2c_of_probe_component(struct device *dev, const char *type, const struct i2
 			continue;
 
 		/* Found a device that is responding */
+		i2c_of_probe_free_gpios(&probe_data);
 		ret = i2c_of_probe_enable_node(dev, node);
 		break;
 	}
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index dbcdb8edbf6f..0da1edddb5a2 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -1037,9 +1037,11 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node,
 /**
  * i2c_of_probe_opts - I2C OF component prober customization options
  * @post_power_on_delay_us: Delay in ms after regulators are powered on. Passed to msleep().
+ * @post_reset_deassert_delay_ms: Delay in ms after GPIOs are set. Passed to msleep().
  */
 struct i2c_of_probe_opts {
 	unsigned int post_power_on_delay_ms;
+	unsigned int post_reset_deassert_delay_ms;
 };
 
 int i2c_of_probe_component(struct device *dev, const char *type, const struct i2c_of_probe_opts *opts);
