+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(CONFIG_SOC_MX6Q)
+#define IOMUXC_SW_MUX_CTL_PAD_EIM_DATA21 0x020e00a4
+#define IOMUXC_SW_MUX_CTL_PAD_EIM_DATA28 0x020e00c4
+#define IOMUXC_SW_PAD_CTL_PAD_EIM_DATA21 0x020e03b8
+#define IOMUXC_SW_PAD_CTL_PAD_EIM_DATA28 0x020e03d8
+#define IOMUXC_SW_SEL_INPUT_PAD_EIM_DATA21 0x020e0898
+#define IOMUXC_SW_SEL_INPUT_PAD_EIM_DATA28 0x020e089c
+#define I2C1_SEL_INPUT_VAL 0
+#endif
+#if defined(CONFIG_SOC_MX6DL) || defined(CONFIG_SOC_MX6S)
+#define IOMUXC_SW_MUX_CTL_PAD_EIM_DATA21 0x020e0158
+#define IOMUXC_SW_MUX_CTL_PAD_EIM_DATA28 0x020e0174
+#define IOMUXC_SW_PAD_CTL_PAD_EIM_DATA21 0x020e0528
+#define IOMUXC_SW_PAD_CTL_PAD_EIM_DATA28 0x020e0544
+#define IOMUXC_SW_SEL_INPUT_PAD_EIM_DATA21 0x020e0868
+#define IOMUXC_SW_SEL_INPUT_PAD_EIM_DATA28 0x020e086c
+#define I2C1_SEL_INPUT_VAL 1
+#endif
+
+#define GPIO_DR 0
+#define GPIO_DIR 4
+#define GPIO_PSR 8
+
+static void tx6_i2c_recover(void)
+{
+ int i;
+ int bad = 0;
+#define SCL_BIT (1 << (TX6_I2C1_SCL_GPIO % 32))
+#define SDA_BIT (1 << (TX6_I2C1_SDA_GPIO % 32))
+
+ if ((readl(GPIO3_BASE_ADDR + GPIO_PSR) &
+ (SCL_BIT | SDA_BIT)) == (SCL_BIT | SDA_BIT))
+ return;
+
+ debug("Clearing I2C bus\n");
+ if (!(readl(GPIO3_BASE_ADDR + GPIO_PSR) & SCL_BIT)) {
+ printf("I2C SCL stuck LOW\n");
+ bad++;
+
+ writel(readl(GPIO3_BASE_ADDR + GPIO_DR) | SCL_BIT,
+ GPIO3_BASE_ADDR + GPIO_DR);
+ writel(readl(GPIO3_BASE_ADDR + GPIO_DIR) | SCL_BIT,
+ GPIO3_BASE_ADDR + GPIO_DIR);
+ }
+ if (!(readl(GPIO3_BASE_ADDR + GPIO_PSR) & SDA_BIT)) {
+ printf("I2C SDA stuck LOW\n");
+ bad++;
+
+ writel(readl(GPIO3_BASE_ADDR + GPIO_DIR) & ~SDA_BIT,
+ GPIO3_BASE_ADDR + GPIO_DIR);
+ writel(readl(GPIO3_BASE_ADDR + GPIO_DR) | SCL_BIT,
+ GPIO3_BASE_ADDR + GPIO_DR);
+ writel(readl(GPIO3_BASE_ADDR + GPIO_DIR) | SCL_BIT,
+ GPIO3_BASE_ADDR + GPIO_DIR);
+
+ 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(GPIO3_BASE_ADDR + GPIO_DR) ^ SCL_BIT;
+
+ debug("%sing SCL\n", (reg & SCL_BIT) ? "Sett" : "Clear");
+ writel(reg, GPIO3_BASE_ADDR + GPIO_DR);
+ udelay(10);
+ if (reg & SCL_BIT &&
+ readl(GPIO3_BASE_ADDR + GPIO_PSR) & SDA_BIT)
+ break;
+ }
+ }
+ if (bad) {
+ u32 reg = readl(GPIO3_BASE_ADDR + GPIO_PSR);
+
+ if ((reg & (SCL_BIT | SDA_BIT)) == (SCL_BIT | SDA_BIT)) {
+ printf("I2C bus recovery succeeded\n");
+ } else {
+ printf("I2C bus recovery FAILED: %08x:%08x\n", reg,
+ SCL_BIT | SDA_BIT);
+ }
+ }
+ debug("Setting up I2C Pads\n");
+ imx_iomux_v3_setup_multiple_pads(tx6_i2c_pads,
+ ARRAY_SIZE(tx6_i2c_pads));
+}
+