pci: Make Rockchip PCIe voltage regulators optional
[oweals/u-boot.git] / drivers / i2c / s3c24x0_i2c.c
index 55c6a12aaed1d92116affa1ba8cae953f5ec8700..5907217981dc3b68ca91ea0228dbb2e378541a81 100644 (file)
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (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.
  */
 
 #include <common.h>
-#if defined(CONFIG_S3C2400)
-#include <s3c2400.h>
-#elif defined(CONFIG_S3C2410)
-#include <s3c2410.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
+#include <log.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/pinmux.h>
+#else
+#include <asm/arch/s3c24x0_cpu.h>
 #endif
-
 #include <asm/io.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_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 */
-
-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
-}
-
-#if 0
-static void SetI2CSDA(int x)
-{
-       rGPEDAT = (rGPEDAT & ~0x8000) | (x & 1) << 15;
-}
+#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
 
-static void SetI2CSCL(int x)
-{
-       struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
+DECLARE_GLOBAL_DATA_PTR;
 
-#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
-}
+/*
+ * 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 int WaitForXfer(void)
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-       int i;
-
-       i = I2C_TIMEOUT * 10000;
-       while (!(readl(&i2c->IICCON) & I2CCON_IRPND) && (i > 0)) {
-               udelay(100);
-               i--;
-       }
-
-       return (readl(&i2c->IICCON) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
-}
+       ulong start_time = get_timer(0);
 
-static int IsACK(void)
-{
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
+       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->IICSTAT) & I2CSTAT_NACK);
+       return I2C_NOK_TOUT;
 }
 
-static void ReadWriteByte(void)
+static void read_write_byte(struct s3c24x0_i2c *i2c)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
-       writel(readl(&i2c->IICCON) & ~I2CCON_IRPND, &i2c->IICCON);
+       clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
 }
 
-void i2c_init(int speed, int slaveadd)
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-       struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
        ulong freq, pres = 16, div;
-       int i;
-
-       /* 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 ((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);
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
+       freq = get_i2c_clk();
+#else
+       freq = get_PCLK();
 #endif
-       }
-
        /* calculate prescaler and divisor values */
-       freq = get_PCLK();
        if ((freq / pres / (16 + 1)) > speed)
                /* set prescaler to 512 */
                pres = 512;
@@ -185,16 +72,26 @@ void i2c_init(int speed, int slaveadd)
        while ((freq / pres / (div + 1)) > speed)
                div++;
 
-       /* set prescaler, divisor according to freq, also set
-        * ACKGEN, IRQ */
-       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->IICCON);
+       /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
 
        /* init to SLAVE REVEIVE and set slaveaddr */
-       writel(0, &i2c->IICSTAT);
-       writel(slaveadd, &i2c->IICADD);
+       writel(0, &i2c->iicstat);
+       writel(slaveadd, &i2c->iicadd);
        /* program Master Transmit (and implicit STOP) */
-       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->IICSTAT);
+       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
 
+       i2c_bus->clock_frequency = speed;
+
+       i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
+                   SYS_I2C_S3C24X0_SLAVE_ADDR);
+
+       return 0;
 }
 
 /*
@@ -204,158 +101,116 @@ void i2c_init(int speed, int slaveadd)
  * by the char, we could make it larger if needed. If it is
  * 0 we skip the address write cycle.
  */
-static
-int i2c_transfer(unsigned char cmd_type,
-                unsigned char chip,
-                unsigned char addr[],
-                unsigned char addr_len,
-                unsigned char data[], unsigned short data_len)
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+                       unsigned char cmd_type,
+                       unsigned char chip,
+                       unsigned char addr[],
+                       unsigned char addr_len,
+                       unsigned char data[],
+                       unsigned short data_len)
 {
-       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-       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 */
-               printf("i2c_transfer: bad call\n");
+               debug("i2c_transfer: bad call\n");
                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) | 0x80, &i2c->IICCON);
-       result = I2C_OK;
+       writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
+
+       /* 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;
+       }
 
        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();
-                               writel(addr[i], &i2c->IICDS);
-                               ReadWriteByte();
-                               i++;
-                       }
-                       i = 0;
-                       while ((i < data_len) && (result == I2C_OK)) {
-                               result = WaitForXfer();
-                               writel(data[i], &i2c->IICDS);
-                               ReadWriteByte();
-                               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();
-                               writel(data[i], &i2c->IICDS);
-                               ReadWriteByte();
-                               i++;
-                       }
+               while ((i < data_len) && (result == I2C_OK)) {
+                       writel(data[i++], &i2c->iicds);
+                       read_write_byte(i2c);
+                       result = WaitForXfer(i2c);
                }
-
-               if (result == I2C_OK)
-                       result = WaitForXfer();
-
-               /* send STOP */
-               writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT);
-               ReadWriteByte();
                break;
 
        case I2C_READ:
                if (addr && addr_len) {
-                       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->IICSTAT);
-                       writel(chip, &i2c->IICDS);
-                       /* send START */
-                       writel(readl(&i2c->IICSTAT) | I2C_START_STOP,
-                              &i2c->IICSTAT);
-                       result = WaitForXfer();
-                       if (IsACK()) {
-                               i = 0;
-                               while ((i < addr_len) && (result == I2C_OK)) {
-                                       writel(addr[i], &i2c->IICDS);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
-                                       i++;
-                               }
-
-                               writel(chip, &i2c->IICDS);
-                               /* resend START */
-                               writel(I2C_MODE_MR | I2C_TXRX_ENA |
-                                      I2C_START_STOP, &i2c->IICSTAT);
-                               ReadWriteByte();
-                               result = WaitForXfer();
-                               i = 0;
-                               while ((i < data_len) && (result == I2C_OK)) {
-                                       /* disable ACK for final READ */
-                                       if (i == data_len - 1)
-                                               writel(readl(&i2c->IICCON)
-                                                      & ~0x80, &i2c->IICCON);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
-                                       data[i] = readl(&i2c->IICDS);
-                                       i++;
-                               }
-                       } else {
-                               result = I2C_NACK;
-                       }
-
-               } else {
-                       writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT);
-                       writel(chip, &i2c->IICDS);
-                       /* send START */
-                       writel(readl(&i2c->IICSTAT) | I2C_START_STOP,
-                              &i2c->IICSTAT);
-                       result = WaitForXfer();
-
-                       if (IsACK()) {
-                               i = 0;
-                               while ((i < data_len) && (result == I2C_OK)) {
-                                       /* disable ACK for final READ */
-                                       if (i == data_len - 1)
-                                               writel(readl(&i2c->IICCON) &
-                                                      ~0x80, &i2c->IICCON);
-                                       ReadWriteByte();
-                                       result = WaitForXfer();
-                                       data[i] = readl(&i2c->IICDS);
-                                       i++;
-                               }
-                       } else {
-                               result = I2C_NACK;
-                       }
+                       /*
+                        * Register address has been sent, now send slave chip
+                        * address again to start the actual read transaction.
+                        */
+                       writel(chip, &i2c->iicds);
+
+                       /* Generate a re-START. */
+                       writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
+                               &i2c->iicstat);
+                       read_write_byte(i2c);
+                       result = WaitForXfer(i2c);
+
+                       if (result != I2C_OK)
+                               goto bailout;
                }
 
-               /* send STOP */
-               writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->IICSTAT);
-               ReadWriteByte();
+               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:
-               printf("i2c_transfer: bad call\n");
+               debug("i2c_transfer: bad call\n");
                result = I2C_NOK;
                break;
        }
 
-       return (result);
+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_bus *i2c_bus = dev_get_priv(dev);
        uchar buf[1];
+       int ret;
 
        buf[0] = 0;
 
@@ -364,84 +219,130 @@ 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_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
+       ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, 0, 0, buf, 1);
+
+       return ret != I2C_OK;
 }
 
-int i2c_read(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)
 {
-       uchar xaddr[4];
-       int ret;
-
-       if (alen > 4) {
-               printf("I2C read: 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;
-       }
+err:
+       return ret;
+}
 
-#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
-       if ((ret =
-            i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-                         buffer, len)) != 0) {
-               printf("I2c read: failed %d\n", ret);
-               return 1;
+static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+                           int nmsgs)
+{
+       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;
+               }
        }
-       return 0;
+
+       for (ret = 0, i = 0; !ret && i < nmsgs; i++)
+               ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
+
+       /* Send STOP */
+       writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
+       read_write_byte(i2c);
+
+       return ret ? -EREMOTEIO : 0;
 }
 
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
 {
-       uchar xaddr[4];
+       const void *blob = gd->fdt_blob;
+       struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+       int node;
 
-       if (alen > 4) {
-               printf("I2C write: addr len %d not supported\n", alen);
-               return 1;
-       }
+       node = dev_of_offset(dev);
 
-       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
-       return (i2c_transfer
-               (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
-                len) != 0);
+       i2c_bus->regs = (struct s3c24x0_i2c *)devfdt_get_addr(dev);
+
+       i2c_bus->id = pinmux_decode_periph_id(blob, node);
+
+       i2c_bus->clock_frequency =
+               dev_read_u32_default(dev, "clock-frequency",
+                                    I2C_SPEED_STANDARD_RATE);
+       i2c_bus->node = node;
+       i2c_bus->bus_num = dev->seq;
+
+       exynos_pinmux_config(i2c_bus->id, 0);
+
+       i2c_bus->active = true;
+
+       return 0;
 }
-#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,
+};