]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/i2c/s3c24x0_i2c.c
Remove CONFIG_SYS_BOOTCOUNT_SINGLEWORD
[people/ms/u-boot.git] / drivers / i2c / s3c24x0_i2c.c
index 382e4c2ecf5853de2d1e6d96b3ea7bd1a3a8f0b3..996a6510a34ea96dc070fff1770879013eb8e5ad 100644 (file)
@@ -2,31 +2,12 @@
  * (C) Copyright 2002
  * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-/* This code should work for both the S3C2400 and the S3C2410
- * as they seem to have the same I2C controller inside.
- * The different address mapping is handled by the s3c24xx.h files below.
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <errno.h>
+#include <dm.h>
 #include <fdtdec.h>
 #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 #include <asm/arch/clk.h>
 #include <i2c.h>
 #include "s3c24x0_i2c.h"
 
-#ifdef CONFIG_HARD_I2C
-
-#define        I2C_WRITE       0
-#define I2C_READ       1
-
-#define I2C_OK         0
-#define I2C_NOK                1
-#define I2C_NACK       2
-#define I2C_NOK_LA     3       /* Lost arbitration */
-#define I2C_NOK_TOUT   4       /* time out */
-
-#define I2CSTAT_BSY    0x20    /* Busy bit */
-#define I2CSTAT_NACK   0x01    /* Nack bit */
-#define I2CCON_ACKGEN  0x80    /* Acknowledge generation */
-#define I2CCON_IRPND   0x10    /* Interrupt pending bit */
-#define I2C_MODE_MT    0xC0    /* Master Transmit Mode */
-#define I2C_MODE_MR    0x80    /* Master Receive Mode */
-#define I2C_START_STOP 0x20    /* START / STOP */
-#define I2C_TXRX_ENA   0x10    /* I2C Tx/Rx enable */
-
-#define I2C_TIMEOUT 1          /* 1 second */
+#ifndef CONFIG_SYS_I2C_S3C24X0_SLAVE
+#define SYS_I2C_S3C24X0_SLAVE_ADDR     0
+#else
+#define SYS_I2C_S3C24X0_SLAVE_ADDR     CONFIG_SYS_I2C_S3C24X0_SLAVE
+#endif
 
+DECLARE_GLOBAL_DATA_PTR;
 
 /*
- * For SPL boot some boards need i2c before SDRAM is initialised so force
- * variables to live in SRAM
+ * Wait til the byte transfer is completed.
+ *
+ * @param i2c- pointer to the appropriate i2c register bank.
+ * @return I2C_OK, if transmission was ACKED
+ *         I2C_NACK, if transmission was NACKED
+ *         I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS
  */
-static unsigned int g_current_bus __attribute__((section(".data")));
-#ifdef CONFIG_OF_CONTROL
-static int i2c_busses __attribute__((section(".data")));
-static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
-                       __attribute__((section(".data")));
-#endif
-
-#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
-static int GetI2CSDA(void)
-{
-       struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-
-#ifdef CONFIG_S3C2410
-       return (readl(&gpio->gpedat) & 0x8000) >> 15;
-#endif
-#ifdef CONFIG_S3C2400
-       return (readl(&gpio->pgdat) & 0x0020) >> 5;
-#endif
-}
-
-static void SetI2CSCL(int x)
-{
-       struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-
-#ifdef CONFIG_S3C2410
-       writel((readl(&gpio->gpedat) & ~0x4000) |
-                                       (x & 1) << 14, &gpio->gpedat);
-#endif
-#ifdef CONFIG_S3C2400
-       writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
-#endif
-}
-#endif
 
 static int WaitForXfer(struct s3c24x0_i2c *i2c)
 {
-       int i;
+       ulong start_time = get_timer(0);
 
-       i = I2C_TIMEOUT * 10000;
-       while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) {
-               udelay(100);
-               i--;
-       }
+       do {
+               if (readl(&i2c->iiccon) & I2CCON_IRPND)
+                       return (readl(&i2c->iicstat) & I2CSTAT_NACK) ?
+                               I2C_NACK : I2C_OK;
+       } while (get_timer(start_time) < I2C_TIMEOUT_MS);
 
-       return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
+       return I2C_NOK_TOUT;
 }
 
-static int IsACK(struct s3c24x0_i2c *i2c)
+static void read_write_byte(struct s3c24x0_i2c *i2c)
 {
-       return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
-}
-
-static void ReadWriteByte(struct s3c24x0_i2c *i2c)
-{
-       writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
-}
-
-static struct s3c24x0_i2c *get_base_i2c(void)
-{
-#ifdef CONFIG_EXYNOS4
-       struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
-                                                       + (EXYNOS4_I2C_SPACING
-                                                       * g_current_bus));
-       return i2c;
-#elif defined CONFIG_EXYNOS5
-       struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
-                                                       + (EXYNOS5_I2C_SPACING
-                                                       * g_current_bus));
-       return i2c;
-#else
-       return s3c24x0_get_base_i2c();
-#endif
+       clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
 }
 
 static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
@@ -167,100 +82,18 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
        writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
 }
 
-/*
- * MULTI BUS I2C support
- */
-
-#ifdef CONFIG_I2C_MULTI_BUS
-int i2c_set_bus_num(unsigned int bus)
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 {
-       struct s3c24x0_i2c *i2c;
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
 
-       if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) {
-               debug("Bad bus: %d\n", bus);
-               return -1;
-       }
+       i2c_bus->clock_frequency = speed;
 
-       g_current_bus = bus;
-       i2c = get_base_i2c();
-       i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+       i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
+                   SYS_I2C_S3C24X0_SLAVE_ADDR);
 
        return 0;
 }
 
-unsigned int i2c_get_bus_num(void)
-{
-       return g_current_bus;
-}
-#endif
-
-void i2c_init(int speed, int slaveadd)
-{
-       struct s3c24x0_i2c *i2c;
-#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
-       struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-#endif
-       int i;
-
-       /* By default i2c channel 0 is the current bus */
-       g_current_bus = 0;
-       i2c = get_base_i2c();
-
-       /* wait for some time to give previous transfer a chance to finish */
-       i = I2C_TIMEOUT * 1000;
-       while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
-               udelay(1000);
-               i--;
-       }
-
-#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
-       if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
-#ifdef CONFIG_S3C2410
-               ulong old_gpecon = readl(&gpio->gpecon);
-#endif
-#ifdef CONFIG_S3C2400
-               ulong old_gpecon = readl(&gpio->pgcon);
-#endif
-               /* bus still busy probably by (most) previously interrupted
-                  transfer */
-
-#ifdef CONFIG_S3C2410
-               /* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */
-               writel((readl(&gpio->gpecon) & ~0xF0000000) | 0x10000000,
-                      &gpio->gpecon);
-#endif
-#ifdef CONFIG_S3C2400
-               /* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */
-               writel((readl(&gpio->pgcon) & ~0x00003c00) | 0x00001000,
-                      &gpio->pgcon);
-#endif
-
-               /* toggle I2CSCL until bus idle */
-               SetI2CSCL(0);
-               udelay(1000);
-               i = 10;
-               while ((i > 0) && (GetI2CSDA() != 1)) {
-                       SetI2CSCL(1);
-                       udelay(1000);
-                       SetI2CSCL(0);
-                       udelay(1000);
-                       i--;
-               }
-               SetI2CSCL(1);
-               udelay(1000);
-
-               /* restore pin functions */
-#ifdef CONFIG_S3C2410
-               writel(old_gpecon, &gpio->gpecon);
-#endif
-#ifdef CONFIG_S3C2400
-               writel(old_gpecon, &gpio->pgcon);
-#endif
-       }
-#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */
-       i2c_ch_init(i2c, speed, slaveadd);
-}
-
 /*
  * cmd_type is 0 for write, 1 for read.
  *
@@ -276,7 +109,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
                        unsigned char data[],
                        unsigned short data_len)
 {
-       int i, result;
+       int i = 0, result;
+       ulong start_time = get_timer(0);
 
        if (data == 0 || data_len == 0) {
                /*Don't support data transfer of no length or to address 0 */
@@ -284,128 +118,78 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
                return I2C_NOK;
        }
 
-       /* Check I2C bus idle */
-       i = I2C_TIMEOUT * 1000;
-       while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
-               udelay(1000);
-               i--;
+       while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+               if (get_timer(start_time) > I2C_TIMEOUT_MS)
+                       return I2C_NOK_TOUT;
        }
 
-       if (readl(&i2c->iicstat) & I2CSTAT_BSY)
-               return I2C_NOK_TOUT;
-
        writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
-       result = I2C_OK;
 
-       switch (cmd_type) {
-       case I2C_WRITE:
-               if (addr && addr_len) {
-                       writel(chip, &i2c->iicds);
-                       /* send START */
-                       writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
-                              &i2c->iicstat);
-                       i = 0;
-                       while ((i < addr_len) && (result == I2C_OK)) {
-                               result = WaitForXfer(i2c);
-                               writel(addr[i], &i2c->iicds);
-                               ReadWriteByte(i2c);
-                               i++;
-                       }
-                       i = 0;
-                       while ((i < data_len) && (result == I2C_OK)) {
-                               result = WaitForXfer(i2c);
-                               writel(data[i], &i2c->iicds);
-                               ReadWriteByte(i2c);
-                               i++;
-                       }
-               } else {
-                       writel(chip, &i2c->iicds);
-                       /* send START */
-                       writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
-                              &i2c->iicstat);
-                       i = 0;
-                       while ((i < data_len) && (result == I2C_OK)) {
-                               result = WaitForXfer(i2c);
-                               writel(data[i], &i2c->iicds);
-                               ReadWriteByte(i2c);
-                               i++;
-                       }
+       /* Get the slave chip address going */
+       writel(chip, &i2c->iicds);
+       if ((cmd_type == I2C_WRITE) || (addr && addr_len))
+               writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
+                      &i2c->iicstat);
+       else
+               writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
+                      &i2c->iicstat);
+
+       /* Wait for chip address to transmit. */
+       result = WaitForXfer(i2c);
+       if (result != I2C_OK)
+               goto bailout;
+
+       /* If register address needs to be transmitted - do it now. */
+       if (addr && addr_len) {
+               while ((i < addr_len) && (result == I2C_OK)) {
+                       writel(addr[i++], &i2c->iicds);
+                       read_write_byte(i2c);
+                       result = WaitForXfer(i2c);
                }
+               i = 0;
+               if (result != I2C_OK)
+                       goto bailout;
+       }
 
-               if (result == I2C_OK)
+       switch (cmd_type) {
+       case I2C_WRITE:
+               while ((i < data_len) && (result == I2C_OK)) {
+                       writel(data[i++], &i2c->iicds);
+                       read_write_byte(i2c);
                        result = WaitForXfer(i2c);
-
-               /* send STOP */
-               writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-               ReadWriteByte(i2c);
+               }
                break;
 
        case I2C_READ:
                if (addr && addr_len) {
+                       /*
+                        * Register address has been sent, now send slave chip
+                        * address again to start the actual read transaction.
+                        */
                        writel(chip, &i2c->iicds);
-                       /* send START */
-                       writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
-                               &i2c->iicstat);
-                       result = WaitForXfer(i2c);
-                       if (IsACK(i2c)) {
-                               i = 0;
-                               while ((i < addr_len) && (result == I2C_OK)) {
-                                       writel(addr[i], &i2c->iicds);
-                                       ReadWriteByte(i2c);
-                                       result = WaitForXfer(i2c);
-                                       i++;
-                               }
-
-                               writel(chip, &i2c->iicds);
-                               /* resend START */
-                               writel(I2C_MODE_MR | I2C_TXRX_ENA |
-                                      I2C_START_STOP, &i2c->iicstat);
-                       ReadWriteByte(i2c);
-                       result = WaitForXfer(i2c);
-                               i = 0;
-                               while ((i < data_len) && (result == I2C_OK)) {
-                                       /* disable ACK for final READ */
-                                       if (i == data_len - 1)
-                                               writel(readl(&i2c->iiccon)
-                                                       & ~I2CCON_ACKGEN,
-                                                       &i2c->iiccon);
-                               ReadWriteByte(i2c);
-                               result = WaitForXfer(i2c);
-                                       data[i] = readl(&i2c->iicds);
-                                       i++;
-                               }
-                       } else {
-                               result = I2C_NACK;
-                       }
-
-               } else {
-                       writel(chip, &i2c->iicds);
-                       /* send START */
+
+                       /* Generate a re-START. */
                        writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
                                &i2c->iicstat);
+                       read_write_byte(i2c);
                        result = WaitForXfer(i2c);
 
-                       if (IsACK(i2c)) {
-                               i = 0;
-                               while ((i < data_len) && (result == I2C_OK)) {
-                                       /* disable ACK for final READ */
-                                       if (i == data_len - 1)
-                                               writel(readl(&i2c->iiccon) &
-                                                       ~I2CCON_ACKGEN,
-                                                       &i2c->iiccon);
-                                       ReadWriteByte(i2c);
-                                       result = WaitForXfer(i2c);
-                                       data[i] = readl(&i2c->iicds);
-                                       i++;
-                               }
-                       } else {
-                               result = I2C_NACK;
-                       }
+                       if (result != I2C_OK)
+                               goto bailout;
                }
 
-               /* send STOP */
-               writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-               ReadWriteByte(i2c);
+               while ((i < data_len) && (result == I2C_OK)) {
+                       /* disable ACK for final READ */
+                       if (i == data_len - 1)
+                               writel(readl(&i2c->iiccon)
+                                      & ~I2CCON_ACKGEN,
+                                      &i2c->iiccon);
+                       read_write_byte(i2c);
+                       result = WaitForXfer(i2c);
+                       data[i++] = readl(&i2c->iicds);
+               }
+               if (result == I2C_NACK)
+                       result = I2C_OK; /* Normal terminated read. */
                break;
 
        default:
@@ -414,15 +198,20 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
                break;
        }
 
+bailout:
+       /* Send STOP. */
+       writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+       read_write_byte(i2c);
+
        return result;
 }
 
-int i2c_probe(uchar chip)
+static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
 {
-       struct s3c24x0_i2c *i2c;
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
        uchar buf[1];
+       int ret;
 
-       i2c = get_base_i2c();
        buf[0] = 0;
 
        /*
@@ -430,161 +219,129 @@ int i2c_probe(uchar chip)
         * address was <ACK>ed (i.e. there was a chip at that address which
         * drove the data line low).
         */
-       return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
-}
-
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
-       struct s3c24x0_i2c *i2c;
-       uchar xaddr[4];
-       int ret;
-
-       if (alen > 4) {
-               debug("I2C read: addr len %d not supported\n", alen);
-               return 1;
-       }
+       ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
 
-       if (alen > 0) {
-               xaddr[0] = (addr >> 24) & 0xFF;
-               xaddr[1] = (addr >> 16) & 0xFF;
-               xaddr[2] = (addr >> 8) & 0xFF;
-               xaddr[3] = addr & 0xFF;
-       }
-
-#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
-       /*
-        * EEPROM chips that implement "address overflow" are ones
-        * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
-        * address and the extra bits end up in the "chip address"
-        * bit slots. This makes a 24WC08 (1Kbyte) chip look like
-        * four 256 byte chips.
-        *
-        * Note that we consider the length of the address field to
-        * still be one byte because the extra address bits are
-        * hidden in the chip address.
-        */
-       if (alen > 0)
-               chip |= ((addr >> (alen * 8)) &
-                        CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
-#endif
-       i2c = get_base_i2c();
-       ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-                       buffer, len);
-       if (ret != 0) {
-               debug("I2c read: failed %d\n", ret);
-               return 1;
-       }
-       return 0;
+       return ret != I2C_OK;
 }
 
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
+                         int seq)
 {
-       struct s3c24x0_i2c *i2c;
-       uchar xaddr[4];
-
-       if (alen > 4) {
-               debug("I2C write: addr len %d not supported\n", alen);
-               return 1;
+       struct s3c24x0_i2c *i2c = i2c_bus->regs;
+       bool is_read = msg->flags & I2C_M_RD;
+       uint status;
+       uint addr;
+       int ret, i;
+
+       if (!seq)
+               setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+
+       /* Get the slave chip address going */
+       addr = msg->addr << 1;
+       writel(addr, &i2c->iicds);
+       status = I2C_TXRX_ENA | I2C_START_STOP;
+       if (is_read)
+               status |= I2C_MODE_MR;
+       else
+               status |= I2C_MODE_MT;
+       writel(status, &i2c->iicstat);
+       if (seq)
+               read_write_byte(i2c);
+
+       /* Wait for chip address to transmit */
+       ret = WaitForXfer(i2c);
+       if (ret)
+               goto err;
+
+       if (is_read) {
+               for (i = 0; !ret && i < msg->len; i++) {
+                       /* disable ACK for final READ */
+                       if (i == msg->len - 1)
+                               clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
+                       read_write_byte(i2c);
+                       ret = WaitForXfer(i2c);
+                       msg->buf[i] = readl(&i2c->iicds);
+               }
+               if (ret == I2C_NACK)
+                       ret = I2C_OK; /* Normal terminated read */
+       } else {
+               for (i = 0; !ret && i < msg->len; i++) {
+                       writel(msg->buf[i], &i2c->iicds);
+                       read_write_byte(i2c);
+                       ret = WaitForXfer(i2c);
+               }
        }
 
-       if (alen > 0) {
-               xaddr[0] = (addr >> 24) & 0xFF;
-               xaddr[1] = (addr >> 16) & 0xFF;
-               xaddr[2] = (addr >> 8) & 0xFF;
-               xaddr[3] = addr & 0xFF;
-       }
-#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
-       /*
-        * EEPROM chips that implement "address overflow" are ones
-        * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
-        * address and the extra bits end up in the "chip address"
-        * bit slots. This makes a 24WC08 (1Kbyte) chip look like
-        * four 256 byte chips.
-        *
-        * Note that we consider the length of the address field to
-        * still be one byte because the extra address bits are
-        * hidden in the chip address.
-        */
-       if (alen > 0)
-               chip |= ((addr >> (alen * 8)) &
-                        CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
-#endif
-       i2c = get_base_i2c();
-       return (i2c_transfer
-               (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
-                len) != 0);
+err:
+       return ret;
 }
 
-#ifdef CONFIG_OF_CONTROL
-void board_i2c_init(const void *blob)
+static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+                           int nmsgs)
 {
-       int i;
-       int node_list[CONFIG_MAX_I2C_NUM];
-       int count;
-
-       count = fdtdec_find_aliases_for_id(blob, "i2c",
-               COMPAT_SAMSUNG_S3C2440_I2C, node_list,
-               CONFIG_MAX_I2C_NUM);
-
-       for (i = 0; i < count; i++) {
-               struct s3c24x0_i2c_bus *bus;
-               int node = node_list[i];
-
-               if (node <= 0)
-                       continue;
-               bus = &i2c_bus[i];
-               bus->regs = (struct s3c24x0_i2c *)
-                       fdtdec_get_addr(blob, node, "reg");
-               bus->id = pinmux_decode_periph_id(blob, node);
-               bus->node = node;
-               bus->bus_num = i2c_busses++;
-               exynos_pinmux_config(bus->id, 0);
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+       struct s3c24x0_i2c *i2c = i2c_bus->regs;
+       ulong start_time;
+       int ret, i;
+
+       start_time = get_timer(0);
+       while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+               if (get_timer(start_time) > I2C_TIMEOUT_MS) {
+                       debug("Timeout\n");
+                       return -ETIMEDOUT;
+               }
        }
-}
 
-static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
-{
-       if (bus_idx < i2c_busses)
-               return &i2c_bus[bus_idx];
+       for (ret = 0, i = 0; !ret && i < nmsgs; i++)
+               ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
 
-       debug("Undefined bus: %d\n", bus_idx);
-       return NULL;
+       /* Send STOP */
+       writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+       read_write_byte(i2c);
+
+       return ret ? -EREMOTEIO : 0;
 }
 
-int i2c_get_bus_num_fdt(int node)
+static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
 {
-       int i;
+       const void *blob = gd->fdt_blob;
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+       int node;
 
-       for (i = 0; i < i2c_busses; i++) {
-               if (node == i2c_bus[i].node)
-                       return i;
-       }
+       node = dev_of_offset(dev);
 
-       debug("%s: Can't find any matched I2C bus\n", __func__);
-       return -1;
-}
+       i2c_bus->regs = (struct s3c24x0_i2c *)devfdt_get_addr(dev);
 
-int i2c_reset_port_fdt(const void *blob, int node)
-{
-       struct s3c24x0_i2c_bus *i2c;
-       int bus;
+       i2c_bus->id = pinmux_decode_periph_id(blob, node);
 
-       bus = i2c_get_bus_num_fdt(node);
-       if (bus < 0) {
-               debug("could not get bus for node %d\n", node);
-               return -1;
-       }
+       i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
+                                                 "clock-frequency", 100000);
+       i2c_bus->node = node;
+       i2c_bus->bus_num = dev->seq;
 
-       i2c = get_bus(bus);
-       if (!i2c) {
-               debug("get_bus() failed for node node %d\n", node);
-               return -1;
-       }
+       exynos_pinmux_config(i2c_bus->id, 0);
 
-       i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+       i2c_bus->active = true;
 
        return 0;
 }
-#endif
 
-#endif /* CONFIG_HARD_I2C */
+static const struct dm_i2c_ops s3c_i2c_ops = {
+       .xfer           = s3c24x0_i2c_xfer,
+       .probe_chip     = s3c24x0_i2c_probe,
+       .set_bus_speed  = s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id s3c_i2c_ids[] = {
+       { .compatible = "samsung,s3c2440-i2c" },
+       { }
+};
+
+U_BOOT_DRIVER(i2c_s3c) = {
+       .name   = "i2c_s3c",
+       .id     = UCLASS_I2C,
+       .of_match = s3c_i2c_ids,
+       .ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
+       .priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
+       .ops    = &s3c_i2c_ops,
+};