+static const iomux_v3_cfg_t const tx6_i2c_pads[] = {
+ /* internal I2C */
+ MX6_PAD_EIM_D28__I2C1_SDA | TX6_I2C_PAD_CTRL,
+ MX6_PAD_EIM_D21__I2C1_SCL | TX6_I2C_PAD_CTRL,
+};
+
+static const struct gpio const tx6qdl_gpios[] = {
+ /* These two entries are used to forcefully reinitialize the I2C bus */
+ { TX6_I2C1_SCL_GPIO, GPIOFLAG_INPUT, "I2C1 SCL", },
+ { TX6_I2C1_SDA_GPIO, GPIOFLAG_INPUT, "I2C1 SDA", },
+
+ { TX6_RESET_OUT_GPIO, GPIOFLAG_OUTPUT_INIT_HIGH, "#RESET_OUT", },
+ { TX6_FEC_PWR_GPIO, GPIOFLAG_OUTPUT_INIT_HIGH, "FEC PHY PWR", },
+ { TX6_FEC_RST_GPIO, GPIOFLAG_OUTPUT_INIT_LOW, "FEC PHY RESET", },
+ { TX6_FEC_INT_GPIO, GPIOFLAG_INPUT, "FEC PHY INT", },
+};
+
+static int pmic_addr __data;
+
+#if defined(TX6_I2C1_SCL_GPIO) && defined(TX6_I2C1_SDA_GPIO)
+#define SCL_BANK (TX6_I2C1_SCL_GPIO / 32)
+#define SDA_BANK (TX6_I2C1_SDA_GPIO / 32)
+#define SCL_BIT (1 << (TX6_I2C1_SCL_GPIO % 32))
+#define SDA_BIT (1 << (TX6_I2C1_SDA_GPIO % 32))
+
+static void * const gpio_ports[] = {
+ (void *)GPIO1_BASE_ADDR,
+ (void *)GPIO2_BASE_ADDR,
+ (void *)GPIO3_BASE_ADDR,
+ (void *)GPIO4_BASE_ADDR,
+ (void *)GPIO5_BASE_ADDR,
+ (void *)GPIO6_BASE_ADDR,
+ (void *)GPIO7_BASE_ADDR,
+};
+
+static void tx6_i2c_recover(void)
+{
+ int i;
+ int bad = 0;
+ struct gpio_regs *scl_regs = gpio_ports[SCL_BANK];
+ struct gpio_regs *sda_regs = gpio_ports[SDA_BANK];
+
+ if ((readl(&scl_regs->gpio_psr) & SCL_BIT) &&
+ (readl(&sda_regs->gpio_psr) & SDA_BIT))
+ return;
+
+ debug("Clearing I2C bus\n");
+ if (!(readl(&scl_regs->gpio_psr) & SCL_BIT)) {
+ printf("I2C SCL stuck LOW\n");
+ bad++;
+
+ setbits_le32(&scl_regs->gpio_dr, SCL_BIT);
+ setbits_le32(&scl_regs->gpio_dir, SCL_BIT);
+
+ imx_iomux_v3_setup_multiple_pads(tx6_i2c_gpio_pads,
+ ARRAY_SIZE(tx6_i2c_gpio_pads));
+ }
+ if (!(readl(&sda_regs->gpio_psr) & SDA_BIT)) {
+ printf("I2C SDA stuck LOW\n");
+
+ clrbits_le32(&sda_regs->gpio_dir, SDA_BIT);
+ setbits_le32(&scl_regs->gpio_dr, SCL_BIT);
+ setbits_le32(&scl_regs->gpio_dir, SCL_BIT);
+
+ if (!bad++)
+ imx_iomux_v3_setup_multiple_pads(tx6_i2c_gpio_pads,
+ ARRAY_SIZE(tx6_i2c_gpio_pads));
+
+ udelay(10);
+
+ for (i = 0; i < 18; i++) {
+ u32 reg = readl(&scl_regs->gpio_dr) ^ SCL_BIT;
+
+ debug("%sing SCL\n",
+ (reg & SCL_BIT) ? "Sett" : "Clear");
+ writel(reg, &scl_regs->gpio_dr);
+ udelay(5);
+ if (reg & SCL_BIT) {
+ if (readl(&sda_regs->gpio_psr) & SDA_BIT)
+ break;
+ if (!(readl(&scl_regs->gpio_psr) & SCL_BIT))
+ break;
+ break;
+ }
+ }
+ }
+ if (bad) {
+ bool scl = !!(readl(&scl_regs->gpio_psr) & SCL_BIT);
+ bool sda = !!(readl(&sda_regs->gpio_psr) & SDA_BIT);
+
+ if (scl && sda) {
+ printf("I2C bus recovery succeeded\n");
+ } else {
+ printf("I2C bus recovery FAILED: SCL: %d SDA: %d\n",
+ scl, sda);
+ }
+ imx_iomux_v3_setup_multiple_pads(tx6_i2c_pads,
+ ARRAY_SIZE(tx6_i2c_pads));
+ }
+}
+#endif
+