Merge tag '20200316-for-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-i2c into next

i2c: for next
- i2c-gpio: make it possible to run deblock sequence on driver probe
- i2c-gpio: add clock stretching support
- updates the Designware I2C driver for high speed mode,
  fix a bug and add some improvements.
- add DM support for memory based bootcounter driver
diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
index ba56ed5..b06b829 100644
--- a/doc/device-tree-bindings/i2c/i2c-gpio.txt
+++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
@@ -16,6 +16,10 @@
    The resulting transfer speed can be adjusted by setting the delay[us]
    between gpio-toggle operations. Speed [Hz] = 1000000 / 4 * udelay[us],
    It not defined, then default is 5us (~50KHz).
+* i2c-gpio,deblock
+   Run deblocking sequence when the driver gets probed.
+* i2c-gpio,scl-output-only;
+   Set if SCL is an output only
 
 Example:
 
diff --git a/doc/device-tree-bindings/misc/bootcounter.txt b/doc/device-tree-bindings/misc/bootcounter.txt
new file mode 100644
index 0000000..d32fbc3
--- /dev/null
+++ b/doc/device-tree-bindings/misc/bootcounter.txt
@@ -0,0 +1,21 @@
+U-Boot bootcounter Devicetree Binding
+=====================================
+
+The device tree node describes the U-Boot bootcounter
+memory based device binding.
+
+Required properties :
+
+- compatible : "u-boot,bootcount";
+- single-word : set this, if you have only one word space
+    for storing the bootcounter.
+
+Example
+-------
+
+MPC83xx based board:
+
+bootcount@0x13ff8 {
+	compatible = "u-boot,bootcount";
+	reg = <0x13ff8 0x08>;
+};
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 0e506c9..0356f8b 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -106,6 +106,13 @@
 	  pointing to the underlying i2c eeprom device) and an optional 'offset'
 	  property are supported.
 
+config BOOTCOUNT_MEM
+	bool "Support memory based bootcounter"
+	help
+	  Enabling Memory based bootcount, typically in a SoC register which
+	  is not cleared on softreset.
+	  compatible = "u-boot,bootcount";
+
 endmenu
 
 endif
diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
index 73ccfb5..059d40d 100644
--- a/drivers/bootcount/Makefile
+++ b/drivers/bootcount/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 obj-$(CONFIG_BOOTCOUNT_GENERIC)	+= bootcount.o
+obj-$(CONFIG_BOOTCOUNT_MEM)	+= bootcount.o
 obj-$(CONFIG_BOOTCOUNT_AT91)	+= bootcount_at91.o
 obj-$(CONFIG_BOOTCOUNT_AM33XX)	+= bootcount_davinci.o
 obj-$(CONFIG_BOOTCOUNT_RAM)	+= bootcount_ram.o
diff --git a/drivers/bootcount/bootcount.c b/drivers/bootcount/bootcount.c
index 7a6d03d..655dfaf 100644
--- a/drivers/bootcount/bootcount.c
+++ b/drivers/bootcount/bootcount.c
@@ -8,6 +8,7 @@
 #include <cpu_func.h>
 #include <linux/compiler.h>
 
+#if !defined(CONFIG_DM_BOOTCOUNT)
 /* Now implement the generic default functions */
 __weak void bootcount_store(ulong a)
 {
@@ -49,3 +50,94 @@
 		return raw_bootcount_load(reg);
 #endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */
 }
+#else
+#include <dm.h>
+
+/*
+ * struct bootcount_mem_priv - private bootcount mem driver data
+ *
+ * @base: base address used for bootcounter
+ * @singleword: if true use only one 32 bit word for bootcounter
+ */
+struct bootcount_mem_priv {
+	phys_addr_t base;
+	bool singleword;
+};
+
+static int bootcount_mem_get(struct udevice *dev, u32 *a)
+{
+	struct bootcount_mem_priv *priv = dev_get_priv(dev);
+	void *reg = (void *)priv->base;
+	u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+
+	if (priv->singleword) {
+		u32 tmp = raw_bootcount_load(reg);
+
+		if ((tmp & 0xffff0000) != (magic & 0xffff0000))
+			return -ENODEV;
+
+		*a = (tmp & 0x0000ffff);
+	} else {
+		if (raw_bootcount_load(reg + 4) != magic)
+			return -ENODEV;
+
+		*a = raw_bootcount_load(reg);
+	}
+
+	return 0;
+};
+
+static int bootcount_mem_set(struct udevice *dev, const u32 a)
+{
+	struct bootcount_mem_priv *priv = dev_get_priv(dev);
+	void *reg = (void *)priv->base;
+	u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+	uintptr_t flush_start = rounddown(priv->base,
+					  CONFIG_SYS_CACHELINE_SIZE);
+	uintptr_t flush_end;
+
+	if (priv->singleword) {
+		raw_bootcount_store(reg, (magic & 0xffff0000) | a);
+		flush_end = roundup(priv->base + 4,
+				    CONFIG_SYS_CACHELINE_SIZE);
+	} else {
+		raw_bootcount_store(reg, a);
+		raw_bootcount_store(reg + 4, magic);
+		flush_end = roundup(priv->base + 8,
+				    CONFIG_SYS_CACHELINE_SIZE);
+	}
+	flush_dcache_range(flush_start, flush_end);
+
+	return 0;
+};
+
+static const struct bootcount_ops bootcount_mem_ops = {
+	.get = bootcount_mem_get,
+	.set = bootcount_mem_set,
+};
+
+static int bootcount_mem_probe(struct udevice *dev)
+{
+	struct bootcount_mem_priv *priv = dev_get_priv(dev);
+
+	priv->base = (phys_addr_t)dev_read_addr(dev);
+	if (dev_read_bool(dev, "single-word"))
+		priv->singleword = true;
+
+	return 0;
+}
+
+static const struct udevice_id bootcount_mem_ids[] = {
+	{ .compatible = "u-boot,bootcount" },
+	{ }
+};
+
+U_BOOT_DRIVER(bootcount_mem) = {
+	.name	= "bootcount-mem",
+	.id	= UCLASS_BOOTCOUNT,
+	.priv_auto_alloc_size = sizeof(struct bootcount_mem_priv),
+	.probe	= bootcount_mem_probe,
+	.of_match = bootcount_mem_ids,
+	.ops	= &bootcount_mem_ops,
+};
+#endif
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 0b5e70a..088a6f3 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -203,14 +203,16 @@
 	const struct dw_scl_sda_cfg *scl_sda_cfg = NULL;
 	struct i2c_regs *regs = priv->regs;
 	enum i2c_speed_mode i2c_spd;
+	u32 comp_param1;
 	int spk_cnt;
 	int ret;
 
+	comp_param1 = readl(&regs->comp_param1);
+
 	if (priv)
 		scl_sda_cfg = priv->scl_sda_cfg;
 	/* Allow high speed if there is no config, or the config allows it */
-	if (speed >= I2C_SPEED_HIGH_RATE &&
-	    (!scl_sda_cfg || scl_sda_cfg->has_high_speed))
+	if (speed >= I2C_SPEED_HIGH_RATE)
 		i2c_spd = IC_SPEED_MODE_HIGH;
 	else if (speed >= I2C_SPEED_FAST_PLUS_RATE)
 		i2c_spd = IC_SPEED_MODE_FAST_PLUS;
@@ -219,6 +221,13 @@
 	else
 		i2c_spd = IC_SPEED_MODE_STANDARD;
 
+	/* Check is high speed possible and fall back to fast mode if not */
+	if (i2c_spd == IC_SPEED_MODE_HIGH) {
+		if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+				!= DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH)
+			i2c_spd = IC_SPEED_MODE_FAST;
+	}
+
 	/* Get the proper spike-suppression count based on target speed */
 	if (!priv || !priv->has_spk_cnt)
 		spk_cnt = 0;
@@ -231,6 +240,9 @@
 		if (i2c_spd == IC_SPEED_MODE_STANDARD) {
 			config->scl_hcnt = scl_sda_cfg->ss_hcnt;
 			config->scl_lcnt = scl_sda_cfg->ss_lcnt;
+		} else if (i2c_spd == IC_SPEED_MODE_HIGH) {
+			config->scl_hcnt = scl_sda_cfg->hs_hcnt;
+			config->scl_lcnt = scl_sda_cfg->hs_lcnt;
 		} else {
 			config->scl_hcnt = scl_sda_cfg->fs_hcnt;
 			config->scl_lcnt = scl_sda_cfg->fs_lcnt;
@@ -274,7 +286,7 @@
 
 	switch (config.speed_mode) {
 	case IC_SPEED_MODE_HIGH:
-		cntl |= IC_CON_SPD_SS;
+		cntl |= IC_CON_SPD_HS;
 		writel(config.scl_hcnt, &i2c_base->ic_hs_scl_hcnt);
 		writel(config.scl_lcnt, &i2c_base->ic_hs_scl_lcnt);
 		break;
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 61a882c..7ee2361 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -138,22 +138,27 @@
 #define IC_STATUS_TFNF		0x0002
 #define IC_STATUS_ACT		0x0001
 
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH      (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK      (BIT(2) | BIT(3))
+
 /**
  * struct dw_scl_sda_cfg - I2C timing configuration
  *
- * @has_high_speed: Support high speed (3.4Mbps)
  * @ss_hcnt: Standard speed high time in ns
  * @fs_hcnt: Fast speed high time in ns
+ * @hs_hcnt: High speed high time in ns
  * @ss_lcnt: Standard speed low time in ns
  * @fs_lcnt: Fast speed low time in ns
+ * @hs_lcnt: High speed low time in ns
  * @sda_hold: SDA hold time
  */
 struct dw_scl_sda_cfg {
-	bool has_high_speed;
 	u32 ss_hcnt;
 	u32 fs_hcnt;
+	u32 hs_hcnt;
 	u32 ss_lcnt;
 	u32 fs_lcnt;
+	u32 hs_lcnt;
 	u32 sda_hold;
 };
 
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index 4e8fa21..07fdd34 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -32,23 +32,50 @@
 	int udelay;
 	 /* sda, scl */
 	struct gpio_desc gpios[PIN_COUNT];
+
+	int (*get_sda)(struct i2c_gpio_bus *bus);
+	void (*set_sda)(struct i2c_gpio_bus *bus, int bit);
+	void (*set_scl)(struct i2c_gpio_bus *bus, int bit);
 };
 
-static int i2c_gpio_sda_get(struct gpio_desc *sda)
+static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
 {
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
 	return dm_gpio_get_value(sda);
 }
 
-static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
+static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
 {
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
 	if (bit)
 		dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
 	else
 		dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
 }
 
-static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
+static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
 {
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	int count = 0;
+
+	if (bit) {
+		dm_gpio_set_dir_flags(scl, GPIOD_IS_IN);
+		while (!dm_gpio_get_value(scl) && count++ < 100000)
+			udelay(1);
+
+		if (!dm_gpio_get_value(scl))
+			pr_err("timeout waiting on slave to release scl\n");
+	} else {
+		dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+	}
+}
+
+/* variant for output only gpios which cannot support clock stretching */
+static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
+{
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
 	ulong flags = GPIOD_IS_OUT;
 
 	if (bit)
@@ -56,65 +83,60 @@
 	dm_gpio_set_dir_flags(scl, flags);
 }
 
-static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
-			       int delay, uchar bit)
+static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
 {
-	i2c_gpio_scl_set(scl, 0);
+	bus->set_scl(bus, 0);
 	udelay(delay);
-	i2c_gpio_sda_set(sda, bit);
+	bus->set_sda(bus, bit);
 	udelay(delay);
-	i2c_gpio_scl_set(scl, 1);
+	bus->set_scl(bus, 1);
 	udelay(2 * delay);
 }
 
-static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
-			     int delay)
+static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay)
 {
 	int value;
 
-	i2c_gpio_scl_set(scl, 1);
+	bus->set_scl(bus, 1);
 	udelay(delay);
-	value = i2c_gpio_sda_get(sda);
+	value = bus->get_sda(bus);
 	udelay(delay);
-	i2c_gpio_scl_set(scl, 0);
+	bus->set_scl(bus, 0);
 	udelay(2 * delay);
 
 	return value;
 }
 
 /* START: High -> Low on SDA while SCL is High */
-static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
-				int delay)
+static void i2c_gpio_send_start(struct i2c_gpio_bus *bus, int delay)
 {
 	udelay(delay);
-	i2c_gpio_sda_set(sda, 1);
+	bus->set_sda(bus, 1);
 	udelay(delay);
-	i2c_gpio_scl_set(scl, 1);
+	bus->set_scl(bus, 1);
 	udelay(delay);
-	i2c_gpio_sda_set(sda, 0);
+	bus->set_sda(bus, 0);
 	udelay(delay);
 }
 
 /* STOP: Low -> High on SDA while SCL is High */
-static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
-			       int delay)
+static void i2c_gpio_send_stop(struct i2c_gpio_bus *bus, int delay)
 {
-	i2c_gpio_scl_set(scl, 0);
+	bus->set_scl(bus, 0);
 	udelay(delay);
-	i2c_gpio_sda_set(sda, 0);
+	bus->set_sda(bus, 0);
 	udelay(delay);
-	i2c_gpio_scl_set(scl, 1);
+	bus->set_scl(bus, 1);
 	udelay(delay);
-	i2c_gpio_sda_set(sda, 1);
+	bus->set_sda(bus, 1);
 	udelay(delay);
 }
 
 /* ack should be I2C_ACK or I2C_NOACK */
-static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
-			      int delay, int ack)
+static void i2c_gpio_send_ack(struct i2c_gpio_bus *bus, int delay, int ack)
 {
-	i2c_gpio_write_bit(scl, sda, delay, ack);
-	i2c_gpio_scl_set(scl, 0);
+	i2c_gpio_write_bit(bus, delay, ack);
+	bus->set_scl(bus, 0);
 	udelay(delay);
 }
 
@@ -123,44 +145,41 @@
  * to clock any confused device back into an idle state.  Also send a
  * <stop> at the end of the sequence for belts & suspenders.
  */
-static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
-				int delay)
+static void i2c_gpio_send_reset(struct i2c_gpio_bus *bus, int delay)
 {
 	int j;
 
 	for (j = 0; j < 9; j++)
-		i2c_gpio_write_bit(scl, sda, delay, 1);
+		i2c_gpio_write_bit(bus, delay, 1);
 
-	i2c_gpio_send_stop(scl, sda, delay);
+	i2c_gpio_send_stop(bus, delay);
 }
 
 /* Set sda high with low clock, before reading slave data */
-static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
-			      int delay)
+static void i2c_gpio_sda_high(struct i2c_gpio_bus *bus, int delay)
 {
-	i2c_gpio_scl_set(scl, 0);
+	bus->set_scl(bus, 0);
 	udelay(delay);
-	i2c_gpio_sda_set(sda, 1);
+	bus->set_sda(bus, 1);
 	udelay(delay);
 }
 
 /* Send 8 bits and look for an acknowledgement */
-static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
-			       int delay, uchar data)
+static int i2c_gpio_write_byte(struct i2c_gpio_bus *bus, int delay, uchar data)
 {
 	int j;
 	int nack;
 
 	for (j = 0; j < 8; j++) {
-		i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
+		i2c_gpio_write_bit(bus, delay, data & 0x80);
 		data <<= 1;
 	}
 
 	udelay(delay);
 
 	/* Look for an <ACK>(negative logic) and return it */
-	i2c_gpio_sda_high(scl, sda, delay);
-	nack = i2c_gpio_read_bit(scl, sda, delay);
+	i2c_gpio_sda_high(bus, delay);
+	nack = i2c_gpio_read_bit(bus, delay);
 
 	return nack;	/* not a nack is an ack */
 }
@@ -169,31 +188,29 @@
  * if ack == I2C_ACK, ACK the byte so can continue reading, else
  * send I2C_NOACK to end the read.
  */
-static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
-				int delay, int ack)
+static uchar i2c_gpio_read_byte(struct i2c_gpio_bus *bus, int delay, int ack)
 {
 	int  data;
 	int  j;
 
-	i2c_gpio_sda_high(scl, sda, delay);
+	i2c_gpio_sda_high(bus, delay);
 	data = 0;
 	for (j = 0; j < 8; j++) {
 		data <<= 1;
-		data |= i2c_gpio_read_bit(scl, sda, delay);
+		data |= i2c_gpio_read_bit(bus, delay);
 	}
-	i2c_gpio_send_ack(scl, sda, delay, ack);
+	i2c_gpio_send_ack(bus, delay, ack);
 
 	return data;
 }
 
 /* send start and the slave chip address */
-int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
-			uchar chip)
+int i2c_send_slave_addr(struct i2c_gpio_bus *bus, int delay, uchar chip)
 {
-	i2c_gpio_send_start(scl, sda, delay);
+	i2c_gpio_send_start(bus, delay);
 
-	if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
-		i2c_gpio_send_stop(scl, sda, delay);
+	if (i2c_gpio_write_byte(bus, delay, chip)) {
+		i2c_gpio_send_stop(bus, delay);
 		return -EIO;
 	}
 
@@ -204,29 +221,27 @@
 			       uchar *buffer, int len,
 			       bool end_with_repeated_start)
 {
-	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
-	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
 	unsigned int delay = bus->udelay;
 	int failures = 0;
 
 	debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
 
-	if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
+	if (i2c_send_slave_addr(bus, delay, chip << 1)) {
 		debug("i2c_write, no chip responded %02X\n", chip);
 		return -EIO;
 	}
 
 	while (len-- > 0) {
-		if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
+		if (i2c_gpio_write_byte(bus, delay, *buffer++))
 			failures++;
 	}
 
 	if (!end_with_repeated_start) {
-		i2c_gpio_send_stop(scl, sda, delay);
+		i2c_gpio_send_stop(bus, delay);
 		return failures;
 	}
 
-	if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
+	if (i2c_send_slave_addr(bus, delay, (chip << 1) | 0x1)) {
 		debug("i2c_write, no chip responded %02X\n", chip);
 		return -EIO;
 	}
@@ -237,16 +252,14 @@
 static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
 			      uchar *buffer, int len)
 {
-	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
-	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
 	unsigned int delay = bus->udelay;
 
 	debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
 
 	while (len-- > 0)
-		*buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
+		*buffer++ = i2c_gpio_read_byte(bus, delay, len == 0);
 
-	i2c_gpio_send_stop(scl, sda, delay);
+	i2c_gpio_send_stop(bus, delay);
 
 	return 0;
 }
@@ -277,14 +290,12 @@
 static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
 {
 	struct i2c_gpio_bus *bus = dev_get_priv(dev);
-	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
-	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
 	unsigned int delay = bus->udelay;
 	int ret;
 
-	i2c_gpio_send_start(scl, sda, delay);
-	ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
-	i2c_gpio_send_stop(scl, sda, delay);
+	i2c_gpio_send_start(bus, delay);
+	ret = i2c_gpio_write_byte(bus, delay, (chip << 1) | 0);
+	i2c_gpio_send_stop(bus, delay);
 
 	debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
 	      __func__, dev->seq, dev->name, chip, chip_flags, ret);
@@ -295,16 +306,29 @@
 static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
 {
 	struct i2c_gpio_bus *bus = dev_get_priv(dev);
-	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
-	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
 
 	bus->udelay = 1000000 / (speed_hz << 2);
 
-	i2c_gpio_send_reset(scl, sda, bus->udelay);
+	i2c_gpio_send_reset(bus, bus->udelay);
 
 	return 0;
 }
 
+static int i2c_gpio_drv_probe(struct udevice *dev)
+{
+	if (dev_read_bool(dev, "i2c-gpio,deblock")) {
+		/* @200kHz 9 clocks = 44us, 62us is ok */
+		const unsigned int DELAY_ABORT_SEQ = 62;
+		struct i2c_gpio_bus *bus = dev_get_priv(dev);
+
+		return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA],
+					     &bus->gpios[PIN_SCL],
+					     16, 5, DELAY_ABORT_SEQ);
+	}
+
+	return 0;
+}
+
 static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
 {
 	struct i2c_gpio_bus *bus = dev_get_priv(dev);
@@ -320,6 +344,13 @@
 	bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
 				     DEFAULT_UDELAY);
 
+	bus->get_sda = i2c_gpio_sda_get;
+	bus->set_sda = i2c_gpio_sda_set;
+	if (fdtdec_get_bool(blob, node, "i2c-gpio,scl-output-only"))
+		bus->set_scl = i2c_gpio_scl_set_output_only;
+	else
+		bus->set_scl = i2c_gpio_scl_set;
+
 	return 0;
 error:
 	pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
@@ -341,6 +372,7 @@
 	.name	= "i2c-gpio",
 	.id	= UCLASS_I2C,
 	.of_match = i2c_gpio_ids,
+	.probe	= i2c_gpio_drv_probe,
 	.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
 	.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
 	.ops	= &i2c_gpio_ops,
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 2aa3efe..e9ec388 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -501,35 +501,53 @@
 	return dm_gpio_get_value(pin);
 }
 
-static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
-				 struct gpio_desc *scl_pin)
+int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
+			  struct gpio_desc *scl_pin,
+			  unsigned int scl_count,
+			  unsigned int start_count,
+			  unsigned int delay)
 {
-	int counter = 9;
-	int ret = 0;
+	int i, ret = -EREMOTEIO;
 
 	i2c_gpio_set_pin(sda_pin, 1);
 	i2c_gpio_set_pin(scl_pin, 1);
-	udelay(5);
+	udelay(delay);
 
 	/*  Toggle SCL until slave release SDA */
-	while (counter-- >= 0) {
+	while (scl_count-- >= 0) {
 		i2c_gpio_set_pin(scl_pin, 1);
-		udelay(5);
+		udelay(delay);
 		i2c_gpio_set_pin(scl_pin, 0);
-		udelay(5);
-		if (i2c_gpio_get_pin(sda_pin))
+		udelay(delay);
+		if (i2c_gpio_get_pin(sda_pin)) {
+			ret = 0;
 			break;
+		}
+	}
+
+	if (!ret && start_count) {
+		for (i = 0; i < start_count; i++) {
+			/* Send start condition */
+			udelay(delay);
+			i2c_gpio_set_pin(sda_pin, 1);
+			udelay(delay);
+			i2c_gpio_set_pin(scl_pin, 1);
+			udelay(delay);
+			i2c_gpio_set_pin(sda_pin, 0);
+			udelay(delay);
+			i2c_gpio_set_pin(scl_pin, 0);
+		}
 	}
 
 	/* Then, send I2C stop */
 	i2c_gpio_set_pin(sda_pin, 0);
-	udelay(5);
+	udelay(delay);
 
 	i2c_gpio_set_pin(scl_pin, 1);
-	udelay(5);
+	udelay(delay);
 
 	i2c_gpio_set_pin(sda_pin, 1);
-	udelay(5);
+	udelay(delay);
 
 	if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
 		ret = -EREMOTEIO;
@@ -561,7 +579,7 @@
 		goto out_no_pinctrl;
 	}
 
-	ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
+	ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5);
 
 	ret = pinctrl_select_state(bus, "default");
 	if (ret) {
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index 6c0459d..ef5f103 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -14,7 +14,7 @@
 
 struct i2c_eeprom_drv_data {
 	u32 size; /* size in bytes */
-	u32 pagewidth; /* pagesize = 2^pagewidth */
+	u32 pagesize; /* page size in bytes */
 	u32 addr_offset_mask; /* bits in addr used for offset overflow */
 	u32 offset_len; /* size in bytes of offset */
 };
@@ -99,13 +99,11 @@
 	u32 pagesize;
 	u32 size;
 
-	if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
+	if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
 		priv->pagesize = pagesize;
-	} else {
+	else
 		/* 6 bit -> page size of up to 2^63 (should be sufficient) */
-		priv->pagewidth = data->pagewidth;
-		priv->pagesize = (1 << priv->pagewidth);
-	}
+		priv->pagesize = data->pagesize;
 
 	if (dev_read_u32(dev, "size", &size) == 0)
 		priv->size = size;
@@ -158,98 +156,98 @@
 
 static const struct i2c_eeprom_drv_data eeprom_data = {
 	.size = 0,
-	.pagewidth = 0,
+	.pagesize = 1,
 	.addr_offset_mask = 0,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
 	.size = 256,
-	.pagewidth = 3,
+	.pagesize = 8,
 	.addr_offset_mask = 0,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c01a_data = {
 	.size = 128,
-	.pagewidth = 3,
+	.pagesize = 8,
 	.addr_offset_mask = 0,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c02_data = {
 	.size = 256,
-	.pagewidth = 3,
+	.pagesize = 8,
 	.addr_offset_mask = 0,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c04_data = {
 	.size = 512,
-	.pagewidth = 4,
+	.pagesize = 16,
 	.addr_offset_mask = 0x1,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c08_data = {
 	.size = 1024,
-	.pagewidth = 4,
+	.pagesize = 16,
 	.addr_offset_mask = 0x3,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c08a_data = {
 	.size = 1024,
-	.pagewidth = 4,
+	.pagesize = 16,
 	.addr_offset_mask = 0x3,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c16a_data = {
 	.size = 2048,
-	.pagewidth = 4,
+	.pagesize = 16,
 	.addr_offset_mask = 0x7,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24mac402_data = {
 	.size = 256,
-	.pagewidth = 4,
+	.pagesize = 16,
 	.addr_offset_mask = 0,
 	.offset_len = 1,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c32_data = {
 	.size = 4096,
-	.pagewidth = 5,
+	.pagesize = 32,
 	.addr_offset_mask = 0,
 	.offset_len = 2,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c64_data = {
 	.size = 8192,
-	.pagewidth = 5,
+	.pagesize = 32,
 	.addr_offset_mask = 0,
 	.offset_len = 2,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c128_data = {
 	.size = 16384,
-	.pagewidth = 6,
+	.pagesize = 64,
 	.addr_offset_mask = 0,
 	.offset_len = 2,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c256_data = {
 	.size = 32768,
-	.pagewidth = 6,
+	.pagesize = 64,
 	.addr_offset_mask = 0,
 	.offset_len = 2,
 };
 
 static const struct i2c_eeprom_drv_data atmel24c512_data = {
 	.size = 65536,
-	.pagewidth = 6,
+	.pagesize = 64,
 	.addr_offset_mask = 0,
 	.offset_len = 2,
 };
diff --git a/include/i2c.h b/include/i2c.h
index 0faf854..0592001 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -331,6 +331,24 @@
 int i2c_deblock(struct udevice *bus);
 
 /**
+ * i2c_deblock_gpio_loop() - recover a bus from an unknown state by toggling SDA/SCL
+ *
+ * This is the inner logic used for toggling I2C SDA/SCL lines as GPIOs
+ * for deblocking the I2C bus.
+ *
+ * @sda_pin:	SDA GPIO
+ * @scl_pin:	SCL GPIO
+ * @scl_count:	Number of SCL clock cycles generated to deblock SDA
+ * @start_count:Number of I2C start conditions sent after deblocking SDA
+ * @delay:	Delay between SCL clock line changes
+ * @return 0 if OK, -ve on error
+ */
+struct gpio_desc;
+int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, struct gpio_desc *scl_pin,
+			  unsigned int scl_count, unsigned int start_count,
+			  unsigned int delay);
+
+/**
  * struct dm_i2c_ops - driver operations for I2C uclass
  *
  * Drivers should support these operations unless otherwise noted. These
diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h
index b96254a..cd620d5 100644
--- a/include/i2c_eeprom.h
+++ b/include/i2c_eeprom.h
@@ -16,8 +16,6 @@
 struct i2c_eeprom {
 	/* The EEPROM's page size in byte */
 	unsigned long pagesize;
-	/* The EEPROM's page width in bits (pagesize = 2^pagewidth) */
-	unsigned pagewidth;
 	/* The EEPROM's capacity in bytes */
 	unsigned long size;
 };