Merge tag 'u-boot-atmel-fixes-2021.01-b' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / drivers / i2c / designware_i2c.c
index 419d021..c549895 100644 (file)
@@ -1,52 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2009
  * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <i2c.h>
+#include <log.h>
+#include <malloc.h>
 #include <pci.h>
 #include <reset.h>
 #include <asm/io.h>
+#include <linux/delay.h>
 #include "designware_i2c.h"
+#include <dm/device_compat.h>
+#include <linux/err.h>
 
-struct dw_scl_sda_cfg {
-       u32 ss_hcnt;
-       u32 fs_hcnt;
-       u32 ss_lcnt;
-       u32 fs_lcnt;
-       u32 sda_hold;
-};
-
-#ifdef CONFIG_X86
-/* BayTrail HCNT/LCNT/SDA hold time */
-static struct dw_scl_sda_cfg byt_config = {
-       .ss_hcnt = 0x200,
-       .fs_hcnt = 0x55,
-       .ss_lcnt = 0x200,
-       .fs_lcnt = 0x99,
-       .sda_hold = 0x6,
-};
-#endif
-
-struct dw_i2c {
-       struct i2c_regs *regs;
-       struct dw_scl_sda_cfg *scl_sda_cfg;
-       struct reset_ctl reset_ctl;
-};
+/*
+ * This assigned unique hex value is constant and is derived from the two ASCII
+ * letters 'DW' followed by a 16-bit unsigned number
+ */
+#define DW_I2C_COMP_TYPE       0x44570140
 
 #ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
-static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
+static int  dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
 {
        u32 ena = enable ? IC_ENABLE_0B : 0;
 
        writel(ena, &i2c_base->ic_enable);
+
+       return 0;
 }
 #else
-static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
+static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
 {
        u32 ena = enable ? IC_ENABLE_0B : 0;
        int timeout = 100;
@@ -54,7 +42,7 @@ static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
        do {
                writel(ena, &i2c_base->ic_enable);
                if ((readl(&i2c_base->ic_enable_status) & IC_ENABLE_0B) == ena)
-                       return;
+                       return 0;
 
                /*
                 * Wait 10 times the signaling period of the highest I2C
@@ -63,89 +51,314 @@ static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
                 */
                udelay(25);
        } while (timeout--);
-
        printf("timeout in %sabling I2C adapter\n", enable ? "en" : "dis");
+
+       return -ETIMEDOUT;
 }
 #endif
 
-/*
- * i2c_set_bus_speed - Set the i2c speed
- * @speed:     required i2c speed
+/* High and low times in different speed modes (in ns) */
+enum {
+       /* SDA Hold Time */
+       DEFAULT_SDA_HOLD_TIME           = 300,
+};
+
+/**
+ * calc_counts() - Convert a period to a number of IC clk cycles
  *
- * Set the i2c speed.
+ * @ic_clk: Input clock in Hz
+ * @period_ns: Period to represent, in ns
+ * @return calculated count
  */
-static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
-                                          struct dw_scl_sda_cfg *scl_sda_cfg,
-                                          unsigned int speed)
+static uint calc_counts(uint ic_clk, uint period_ns)
 {
-       unsigned int cntl;
-       unsigned int hcnt, lcnt;
-       int i2c_spd;
+       return DIV_ROUND_UP(ic_clk / 1000 * period_ns, NANO_TO_KILO);
+}
+
+/**
+ * struct i2c_mode_info - Information about an I2C speed mode
+ *
+ * Each speed mode has its own characteristics. This struct holds these to aid
+ * calculations in dw_i2c_calc_timing().
+ *
+ * @speed: Speed in Hz
+ * @min_scl_lowtime_ns: Minimum value for SCL low period in ns
+ * @min_scl_hightime_ns: Minimum value for SCL high period in ns
+ * @def_rise_time_ns: Default rise time in ns
+ * @def_fall_time_ns: Default fall time in ns
+ */
+struct i2c_mode_info {
+       int speed;
+       int min_scl_hightime_ns;
+       int min_scl_lowtime_ns;
+       int def_rise_time_ns;
+       int def_fall_time_ns;
+};
+
+static const struct i2c_mode_info info_for_mode[] = {
+       [IC_SPEED_MODE_STANDARD] = {
+               I2C_SPEED_STANDARD_RATE,
+               MIN_SS_SCL_HIGHTIME,
+               MIN_SS_SCL_LOWTIME,
+               1000,
+               300,
+       },
+       [IC_SPEED_MODE_FAST] = {
+               I2C_SPEED_FAST_RATE,
+               MIN_FS_SCL_HIGHTIME,
+               MIN_FS_SCL_LOWTIME,
+               300,
+               300,
+       },
+       [IC_SPEED_MODE_FAST_PLUS] = {
+               I2C_SPEED_FAST_PLUS_RATE,
+               MIN_FP_SCL_HIGHTIME,
+               MIN_FP_SCL_LOWTIME,
+               260,
+               500,
+       },
+       [IC_SPEED_MODE_HIGH] = {
+               I2C_SPEED_HIGH_RATE,
+               MIN_HS_SCL_HIGHTIME,
+               MIN_HS_SCL_LOWTIME,
+               120,
+               120,
+       },
+};
+
+/**
+ * dw_i2c_calc_timing() - Calculate the timings to use for a bus
+ *
+ * @priv: Bus private information (NULL if not using driver model)
+ * @mode: Speed mode to use
+ * @ic_clk: IC clock speed in Hz
+ * @spk_cnt: Spike-suppression count
+ * @config: Returns value to use
+ * @return 0 if OK, -EINVAL if the calculation failed due to invalid data
+ */
+static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
+                             int ic_clk, int spk_cnt,
+                             struct dw_i2c_speed_config *config)
+{
+       int fall_cnt, rise_cnt, min_tlow_cnt, min_thigh_cnt;
+       int hcnt, lcnt, period_cnt, diff, tot;
+       int sda_hold_time_ns, scl_rise_time_ns, scl_fall_time_ns;
+       const struct i2c_mode_info *info;
+
+       /*
+        * Find the period, rise, fall, min tlow, and min thigh in terms of
+        * counts of the IC clock
+        */
+       info = &info_for_mode[mode];
+       period_cnt = ic_clk / info->speed;
+       scl_rise_time_ns = priv && priv->scl_rise_time_ns ?
+                priv->scl_rise_time_ns : info->def_rise_time_ns;
+       scl_fall_time_ns = priv && priv->scl_fall_time_ns ?
+                priv->scl_fall_time_ns : info->def_fall_time_ns;
+       rise_cnt = calc_counts(ic_clk, scl_rise_time_ns);
+       fall_cnt = calc_counts(ic_clk, scl_fall_time_ns);
+       min_tlow_cnt = calc_counts(ic_clk, info->min_scl_lowtime_ns);
+       min_thigh_cnt = calc_counts(ic_clk, info->min_scl_hightime_ns);
+
+       debug("dw_i2c: mode %d, ic_clk %d, speed %d, period %d rise %d fall %d tlow %d thigh %d spk %d\n",
+             mode, ic_clk, info->speed, period_cnt, rise_cnt, fall_cnt,
+             min_tlow_cnt, min_thigh_cnt, spk_cnt);
+
+       /*
+        * Back-solve for hcnt and lcnt according to the following equations:
+        * SCL_High_time = [(HCNT + IC_*_SPKLEN + 7) * ic_clk] + SCL_Fall_time
+        * SCL_Low_time = [(LCNT + 1) * ic_clk] - SCL_Fall_time + SCL_Rise_time
+        */
+       hcnt = min_thigh_cnt - fall_cnt - 7 - spk_cnt;
+       lcnt = min_tlow_cnt - rise_cnt + fall_cnt - 1;
+
+       if (hcnt < 0 || lcnt < 0) {
+               debug("dw_i2c: bad counts. hcnt = %d lcnt = %d\n", hcnt, lcnt);
+               return log_msg_ret("counts", -EINVAL);
+       }
+
+       /*
+        * Now add things back up to ensure the period is hit. If it is off,
+        * split the difference and bias to lcnt for remainder
+        */
+       tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+
+       if (tot < period_cnt) {
+               diff = (period_cnt - tot) / 2;
+               hcnt += diff;
+               lcnt += diff;
+               tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+               lcnt += period_cnt - tot;
+       }
+
+       config->scl_lcnt = lcnt;
+       config->scl_hcnt = hcnt;
+
+       /* Use internal default unless other value is specified */
+       sda_hold_time_ns = priv && priv->sda_hold_time_ns ?
+                priv->sda_hold_time_ns : DEFAULT_SDA_HOLD_TIME;
+       config->sda_hold = calc_counts(ic_clk, sda_hold_time_ns);
+
+       debug("dw_i2c: hcnt = %d lcnt = %d sda hold = %d\n", hcnt, lcnt,
+             config->sda_hold);
+
+       return 0;
+}
 
-       if (speed >= I2C_MAX_SPEED)
-               i2c_spd = IC_SPEED_MODE_MAX;
-       else if (speed >= I2C_FAST_SPEED)
+/**
+ * calc_bus_speed() - Calculate the config to use for a particular i2c speed
+ *
+ * @priv: Private information for the driver (NULL if not using driver model)
+ * @i2c_base: Registers for the I2C controller
+ * @speed: Required i2c speed in Hz
+ * @bus_clk: Input clock to the I2C controller in Hz (e.g. IC_CLK)
+ * @config: Returns the config to use for this speed
+ * @return 0 if OK, -ve on error
+ */
+static int calc_bus_speed(struct dw_i2c *priv, struct i2c_regs *regs, int speed,
+                         ulong bus_clk, struct dw_i2c_speed_config *config)
+{
+       const struct dw_scl_sda_cfg *scl_sda_cfg = NULL;
+       enum i2c_speed_mode i2c_spd;
+       int spk_cnt;
+       int ret;
+
+       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)
+               i2c_spd = IC_SPEED_MODE_HIGH;
+       else if (speed >= I2C_SPEED_FAST_PLUS_RATE)
+               i2c_spd = IC_SPEED_MODE_FAST_PLUS;
+       else if (speed >= I2C_SPEED_FAST_RATE)
                i2c_spd = IC_SPEED_MODE_FAST;
        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) {
+               u32 comp_param1;
+
+               comp_param1 = readl(&regs->comp_param1);
+               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;
+       else if (i2c_spd >= IC_SPEED_MODE_HIGH)
+               spk_cnt = readl(&regs->hs_spklen);
+       else
+               spk_cnt = readl(&regs->fs_spklen);
+       if (scl_sda_cfg) {
+               config->sda_hold = scl_sda_cfg->sda_hold;
+               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;
+               }
+       } else {
+               ret = dw_i2c_calc_timing(priv, i2c_spd, bus_clk, spk_cnt,
+                                        config);
+               if (ret)
+                       return log_msg_ret("gen_confg", ret);
+       }
+       config->speed_mode = i2c_spd;
+
+       return 0;
+}
+
+/**
+ * _dw_i2c_set_bus_speed() - Set the i2c speed
+ *
+ * @priv: Private information for the driver (NULL if not using driver model)
+ * @i2c_base: Registers for the I2C controller
+ * @speed: Required i2c speed in Hz
+ * @bus_clk: Input clock to the I2C controller in Hz (e.g. IC_CLK)
+ * @return 0 if OK, -ve on error
+ */
+static int _dw_i2c_set_bus_speed(struct dw_i2c *priv, struct i2c_regs *i2c_base,
+                                unsigned int speed, unsigned int bus_clk)
+{
+       struct dw_i2c_speed_config config;
+       unsigned int cntl;
+       unsigned int ena;
+       int ret;
+
+       ret = calc_bus_speed(priv, i2c_base, speed, bus_clk, &config);
+       if (ret)
+               return ret;
+
+       /* Get enable setting for restore later */
+       ena = readl(&i2c_base->ic_enable) & IC_ENABLE_0B;
+
        /* to set speed cltr must be disabled */
        dw_i2c_enable(i2c_base, false);
 
        cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
 
-       switch (i2c_spd) {
-#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
-       case IC_SPEED_MODE_MAX:
-               cntl |= IC_CON_SPD_SS;
-               if (scl_sda_cfg) {
-                       hcnt = scl_sda_cfg->fs_hcnt;
-                       lcnt = scl_sda_cfg->fs_lcnt;
-               } else {
-                       hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
-                       lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
-               }
-               writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
-               writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
+       switch (config.speed_mode) {
+       case IC_SPEED_MODE_HIGH:
+               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;
-#endif
-
        case IC_SPEED_MODE_STANDARD:
                cntl |= IC_CON_SPD_SS;
-               if (scl_sda_cfg) {
-                       hcnt = scl_sda_cfg->ss_hcnt;
-                       lcnt = scl_sda_cfg->ss_lcnt;
-               } else {
-                       hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
-                       lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
-               }
-               writel(hcnt, &i2c_base->ic_ss_scl_hcnt);
-               writel(lcnt, &i2c_base->ic_ss_scl_lcnt);
+               writel(config.scl_hcnt, &i2c_base->ic_ss_scl_hcnt);
+               writel(config.scl_lcnt, &i2c_base->ic_ss_scl_lcnt);
                break;
-
+       case IC_SPEED_MODE_FAST_PLUS:
        case IC_SPEED_MODE_FAST:
        default:
                cntl |= IC_CON_SPD_FS;
-               if (scl_sda_cfg) {
-                       hcnt = scl_sda_cfg->fs_hcnt;
-                       lcnt = scl_sda_cfg->fs_lcnt;
-               } else {
-                       hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
-                       lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
-               }
-               writel(hcnt, &i2c_base->ic_fs_scl_hcnt);
-               writel(lcnt, &i2c_base->ic_fs_scl_lcnt);
+               writel(config.scl_hcnt, &i2c_base->ic_fs_scl_hcnt);
+               writel(config.scl_lcnt, &i2c_base->ic_fs_scl_lcnt);
                break;
        }
 
        writel(cntl, &i2c_base->ic_con);
 
        /* Configure SDA Hold Time if required */
-       if (scl_sda_cfg)
-               writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold);
+       if (config.sda_hold)
+               writel(config.sda_hold, &i2c_base->ic_sda_hold);
 
-       /* Enable back i2c now speed set */
-       dw_i2c_enable(i2c_base, true);
+       /* Restore back i2c now speed set */
+       if (ena == IC_ENABLE_0B)
+               dw_i2c_enable(i2c_base, true);
+       if (priv)
+               priv->config = config;
+
+       return 0;
+}
+
+int dw_i2c_gen_speed_config(const struct udevice *dev, int speed_hz,
+                           struct dw_i2c_speed_config *config)
+{
+       struct dw_i2c *priv = dev_get_priv(dev);
+       ulong rate;
+       int ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+       rate = clk_get_rate(&priv->clk);
+       if (IS_ERR_VALUE(rate))
+               return log_msg_ret("clk", -EINVAL);
+#else
+       rate = IC_CLK;
+#endif
+
+       ret = calc_bus_speed(priv, priv->regs, speed_hz, rate, config);
+       if (ret)
+               printf("%s: ret=%d\n", __func__, ret);
+       if (ret)
+               return log_msg_ret("calc_bus_speed", ret);
 
        return 0;
 }
@@ -371,10 +584,14 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr,
  *
  * Initialization function.
  */
-static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
+static int __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
 {
+       int ret;
+
        /* Disable i2c */
-       dw_i2c_enable(i2c_base, false);
+       ret = dw_i2c_enable(i2c_base, false);
+       if (ret)
+               return ret;
 
        writel(IC_CON_SD | IC_CON_RE | IC_CON_SPD_FS | IC_CON_MM,
               &i2c_base->ic_con);
@@ -382,12 +599,16 @@ static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
        writel(IC_TX_TL, &i2c_base->ic_tx_tl);
        writel(IC_STOP_DET, &i2c_base->ic_intr_mask);
 #ifndef CONFIG_DM_I2C
-       __dw_i2c_set_bus_speed(i2c_base, NULL, speed);
+       _dw_i2c_set_bus_speed(NULL, i2c_base, speed, IC_CLK);
        writel(slaveaddr, &i2c_base->ic_sar);
 #endif
 
        /* Enable i2c */
-       dw_i2c_enable(i2c_base, true);
+       ret = dw_i2c_enable(i2c_base, true);
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
 #ifndef CONFIG_DM_I2C
@@ -423,7 +644,7 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap,
                                         unsigned int speed)
 {
        adap->speed = speed;
-       return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed);
+       return _dw_i2c_set_bus_speed(NULL, i2c_get_base(adap), speed, IC_CLK);
 }
 
 static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
@@ -513,8 +734,16 @@ static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
 static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 {
        struct dw_i2c *i2c = dev_get_priv(bus);
+       ulong rate;
 
-       return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed);
+#if CONFIG_IS_ENABLED(CLK)
+       rate = clk_get_rate(&i2c->clk);
+       if (IS_ERR_VALUE(rate))
+               return log_ret(-EINVAL);
+#else
+       rate = IC_CLK;
+#endif
+       return _dw_i2c_set_bus_speed(i2c, i2c->regs, speed, rate);
 }
 
 static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
@@ -533,61 +762,72 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
        return ret;
 }
 
-static int designware_i2c_probe(struct udevice *bus)
+int designware_i2c_ofdata_to_platdata(struct udevice *bus)
 {
        struct dw_i2c *priv = dev_get_priv(bus);
        int ret;
 
-       if (device_is_on_pci_bus(bus)) {
-#ifdef CONFIG_DM_PCI
-               /* Save base address from PCI BAR */
-               priv->regs = (struct i2c_regs *)
-                       dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-#ifdef CONFIG_X86
-               /* Use BayTrail specific timing values */
-               priv->scl_sda_cfg = &byt_config;
-#endif
-#endif
+       if (!priv->regs)
+               priv->regs = dev_read_addr_ptr(bus);
+       dev_read_u32(bus, "i2c-scl-rising-time-ns", &priv->scl_rise_time_ns);
+       dev_read_u32(bus, "i2c-scl-falling-time-ns", &priv->scl_fall_time_ns);
+       dev_read_u32(bus, "i2c-sda-hold-time-ns", &priv->sda_hold_time_ns);
+
+       ret = reset_get_bulk(bus, &priv->resets);
+       if (ret) {
+               if (ret != -ENOTSUPP)
+                       dev_warn(bus, "Can't get reset: %d\n", ret);
        } else {
-               priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
+               reset_deassert_bulk(&priv->resets);
        }
 
-       ret = reset_get_by_name(bus, "i2c", &priv->reset_ctl);
+#if CONFIG_IS_ENABLED(CLK)
+       ret = clk_get_by_index(bus, 0, &priv->clk);
        if (ret)
-               pr_info("reset_get_by_name() failed: %d\n", ret);
+               return ret;
 
-       if (&priv->reset_ctl)
-               reset_deassert(&priv->reset_ctl);
-
-       __dw_i2c_init(priv->regs, 0, 0);
+       ret = clk_enable(&priv->clk);
+       if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+               clk_free(&priv->clk);
+               dev_err(bus, "failed to enable clock\n");
+               return ret;
+       }
+#endif
 
        return 0;
 }
 
-static int designware_i2c_bind(struct udevice *dev)
+int designware_i2c_probe(struct udevice *bus)
 {
-       static int num_cards;
-       char name[20];
+       struct dw_i2c *priv = dev_get_priv(bus);
+       uint comp_type;
 
-       /* Create a unique device name for PCI type devices */
-       if (device_is_on_pci_bus(dev)) {
-               /*
-                * ToDo:
-                * Setting req_seq in the driver is probably not recommended.
-                * But without a DT alias the number is not configured. And
-                * using this driver is impossible for PCIe I2C devices.
-                * This can be removed, once a better (correct) way for this
-                * is found and implemented.
-                */
-               dev->req_seq = num_cards;
-               sprintf(name, "i2c_designware#%u", num_cards++);
-               device_set_name(dev, name);
+       comp_type = readl(&priv->regs->comp_type);
+       if (comp_type != DW_I2C_COMP_TYPE) {
+               log_err("I2C bus %s has unknown type %#x\n", bus->name,
+                       comp_type);
+               return -ENXIO;
        }
 
-       return 0;
+       log_debug("I2C bus %s version %#x\n", bus->name,
+                 readl(&priv->regs->comp_version));
+
+       return __dw_i2c_init(priv->regs, 0, 0);
+}
+
+int designware_i2c_remove(struct udevice *dev)
+{
+       struct dw_i2c *priv = dev_get_priv(dev);
+
+#if CONFIG_IS_ENABLED(CLK)
+       clk_disable(&priv->clk);
+       clk_free(&priv->clk);
+#endif
+
+       return reset_release_bulk(&priv->resets);
 }
 
-static const struct dm_i2c_ops designware_i2c_ops = {
+const struct dm_i2c_ops designware_i2c_ops = {
        .xfer           = designware_i2c_xfer,
        .probe_chip     = designware_i2c_probe_chip,
        .set_bus_speed  = designware_i2c_set_bus_speed,
@@ -602,26 +842,12 @@ U_BOOT_DRIVER(i2c_designware) = {
        .name   = "i2c_designware",
        .id     = UCLASS_I2C,
        .of_match = designware_i2c_ids,
-       .bind   = designware_i2c_bind,
+       .ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
        .probe  = designware_i2c_probe,
        .priv_auto_alloc_size = sizeof(struct dw_i2c),
+       .remove = designware_i2c_remove,
+       .flags  = DM_FLAG_OS_PREPARE,
        .ops    = &designware_i2c_ops,
 };
 
-#ifdef CONFIG_X86
-static struct pci_device_id designware_pci_supported[] = {
-       /* Intel BayTrail has 7 I2C controller located on the PCI bus */
-       { PCI_VDEVICE(INTEL, 0x0f41) },
-       { PCI_VDEVICE(INTEL, 0x0f42) },
-       { PCI_VDEVICE(INTEL, 0x0f43) },
-       { PCI_VDEVICE(INTEL, 0x0f44) },
-       { PCI_VDEVICE(INTEL, 0x0f45) },
-       { PCI_VDEVICE(INTEL, 0x0f46) },
-       { PCI_VDEVICE(INTEL, 0x0f47) },
-       {},
-};
-
-U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
-#endif
-
 #endif /* CONFIG_DM_I2C */