]> git.sur5r.net Git - u-boot/commitdiff
Merge git://git.denx.de/u-boot-i2c
authorTom Rini <trini@konsulko.com>
Wed, 11 Apr 2018 21:00:52 +0000 (17:00 -0400)
committerTom Rini <trini@konsulko.com>
Wed, 11 Apr 2018 21:00:52 +0000 (17:00 -0400)
doc/device-tree-bindings/i2c/i2c.txt
drivers/i2c/fsl_i2c.c
drivers/i2c/i2c-uclass.c
drivers/i2c/ihs_i2c.c

index ea918dd61d5511c20911710f92ec25132914da67..de818d4713f0c6f77f6a63ed0eb315ec5e66e746 100644 (file)
@@ -12,6 +12,11 @@ property which allows the chip offset length to be selected.
 Optional properties:
 - u-boot,i2c-offset-len - length of chip offset in bytes. If omitted the
     default value of 1 is used.
+- gpios = <sda ...>, <scl ...>;
+  pinctrl-names = "default", "gpio";
+  pinctrl-0 = <&i2c_xfer>;
+  pinctrl-1 = <&i2c_gpio>;
+    Pin description for I2C bus software deblocking.
 
 
 Example
@@ -26,3 +31,11 @@ i2c4: i2c@12ca0000 {
                ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
        };
 };
+
+&i2c1 {
+       pinctrl-names = "default", "gpio";
+       pinctrl-0 = <&i2c1_xfer>;
+       pinctrl-1 = <&i2c1_gpio>;
+       gpios = <&gpio1 26 GPIO_ACTIVE_LOW>, /* SDA */
+               <&gpio1 27 GPIO_ACTIVE_LOW>; /* SCL */
+};
index cb0f5ea2333fbe9bb0f6c402fa0a76597ec7162c..450a91ded6b75a008433c1489fbc711f34ed968a 100644 (file)
@@ -12,6 +12,7 @@
 #include <i2c.h>               /* Functional interface */
 #include <asm/io.h>
 #include <asm/fsl_i2c.h>       /* HW definitions */
+#include <clk.h>
 #include <dm.h>
 #include <mapmem.h>
 
@@ -573,11 +574,9 @@ static int fsl_i2c_set_bus_speed(struct udevice *bus, uint speed)
 static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
 {
        struct fsl_i2c_dev *dev = dev_get_priv(bus);
-       fdt_addr_t addr;
+       struct clk clock;
 
-       addr = dev_read_u32_default(bus, "reg", -1);
-
-       dev->base = map_sysmem(CONFIG_SYS_IMMR + addr, sizeof(struct fsl_i2c_base));
+       dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct fsl_i2c_base));
 
        if (!dev->base)
                return -ENOMEM;
@@ -587,7 +586,11 @@ static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
                                             0x7f);
        dev->speed = dev_read_u32_default(bus, "clock-frequency", 400000);
 
-       dev->i2c_clk = dev->index ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
+       if (!clk_get_by_index(bus, 0, &clock))
+               dev->i2c_clk = clk_get_rate(&clock);
+       else
+               dev->i2c_clk = dev->index ? gd->arch.i2c2_clk :
+                                           gd->arch.i2c1_clk;
 
        return 0;
 }
index 920811a075c68454908129497db1809d4bd9ec72..4ac6ef84f58007ca45987b4e3713dc8e501d9027 100644 (file)
 #include <malloc.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <dm/pinctrl.h>
+#ifdef CONFIG_DM_GPIO
+#include <asm/gpio.h>
+#endif
 
 #define I2C_MAX_OFFSET_LEN     4
 
+enum {
+       PIN_SDA = 0,
+       PIN_SCL,
+       PIN_COUNT,
+};
+
 /* Useful debugging function */
 void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
 {
@@ -445,20 +455,110 @@ int i2c_get_chip_offset_len(struct udevice *dev)
        return chip->offset_len;
 }
 
+#ifdef CONFIG_DM_GPIO
+static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
+{
+       if (bit)
+               dm_gpio_set_dir_flags(pin, GPIOD_IS_IN);
+       else
+               dm_gpio_set_dir_flags(pin, GPIOD_IS_OUT |
+                                          GPIOD_ACTIVE_LOW |
+                                          GPIOD_IS_OUT_ACTIVE);
+}
+
+static int i2c_gpio_get_pin(struct gpio_desc *pin)
+{
+       return dm_gpio_get_value(pin);
+}
+
+static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
+                                struct gpio_desc *scl_pin)
+{
+       int counter = 9;
+       int ret = 0;
+
+       i2c_gpio_set_pin(sda_pin, 1);
+       i2c_gpio_set_pin(scl_pin, 1);
+       udelay(5);
+
+       /*  Toggle SCL until slave release SDA */
+       while (counter-- >= 0) {
+               i2c_gpio_set_pin(scl_pin, 1);
+               udelay(5);
+               i2c_gpio_set_pin(scl_pin, 0);
+               udelay(5);
+               if (i2c_gpio_get_pin(sda_pin))
+                       break;
+       }
+
+       /* Then, send I2C stop */
+       i2c_gpio_set_pin(sda_pin, 0);
+       udelay(5);
+
+       i2c_gpio_set_pin(scl_pin, 1);
+       udelay(5);
+
+       i2c_gpio_set_pin(sda_pin, 1);
+       udelay(5);
+
+       if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
+               ret = -EREMOTEIO;
+
+       return ret;
+}
+
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+       struct gpio_desc gpios[PIN_COUNT];
+       int ret, ret0;
+
+       ret = gpio_request_list_by_name(bus, "gpios", gpios,
+                                       ARRAY_SIZE(gpios), GPIOD_IS_IN);
+       if (ret != ARRAY_SIZE(gpios)) {
+               debug("%s: I2C Node '%s' has no 'gpios' property %s\n",
+                     __func__, dev_read_name(bus), bus->name);
+               if (ret >= 0) {
+                       gpio_free_list(bus, gpios, ret);
+                       ret = -ENOENT;
+               }
+               goto out;
+       }
+
+       ret = pinctrl_select_state(bus, "gpio");
+       if (ret) {
+               debug("%s: I2C Node '%s' has no 'gpio' pinctrl state. %s\n",
+                     __func__, dev_read_name(bus), bus->name);
+               goto out_no_pinctrl;
+       }
+
+       ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
+
+       ret = pinctrl_select_state(bus, "default");
+       if (ret) {
+               debug("%s: I2C Node '%s' has no 'default' pinctrl state. %s\n",
+                     __func__, dev_read_name(bus), bus->name);
+       }
+
+       ret = !ret ? ret0 : ret;
+
+out_no_pinctrl:
+       gpio_free_list(bus, gpios, ARRAY_SIZE(gpios));
+out:
+       return ret;
+}
+#else
+static int i2c_deblock_gpio(struct udevice *bus)
+{
+       return -ENOSYS;
+}
+#endif // CONFIG_DM_GPIO
+
 int i2c_deblock(struct udevice *bus)
 {
        struct dm_i2c_ops *ops = i2c_get_ops(bus);
 
-       /*
-        * We could implement a software deblocking here if we could get
-        * access to the GPIOs used by I2C, and switch them to GPIO mode
-        * and then back to I2C. This is somewhat beyond our powers in
-        * driver model at present, so for now just fail.
-        *
-        * See https://patchwork.ozlabs.org/patch/399040/
-        */
        if (!ops->deblock)
-               return -ENOSYS;
+               return i2c_deblock_gpio(bus);
 
        return ops->deblock(bus);
 }
index 92985212200ea311362922e4c6beaca38cbb226b..82abb439f0c17f569e6da4e94fa7e3d6ee6b3e6b 100644 (file)
@@ -99,7 +99,8 @@ static int wait_for_int(bool read)
 #endif
 
 #ifdef CONFIG_DM_I2C
-       fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+       fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+                    FPGAMAP_SIZE_16);
 #else
        I2C_GET_REG(interrupt_status, &val);
 #endif
@@ -110,7 +111,8 @@ static int wait_for_int(bool read)
                if (ctr++ > 5000)
                        return 1;
 #ifdef CONFIG_DM_I2C
-               fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+               fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+                            FPGAMAP_SIZE_16);
 #else
                I2C_GET_REG(interrupt_status, &val);
 #endif
@@ -128,6 +130,7 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
 #endif
 {
        u16 val;
+       u16 data;
 #ifdef CONFIG_DM_I2C
        struct ihs_i2c_priv *priv = dev_get_priv(dev);
        struct udevice *fpga;
@@ -136,13 +139,14 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
 #endif
 
        /* Clear interrupt status */
+       data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
 #ifdef CONFIG_DM_I2C
-       fpgamap_write16(fpga, priv->addr + REG_INTERRUPT_STATUS,
-                       I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
-       fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
+       fpgamap_write(fpga, priv->addr + REG_INTERRUPT_STATUS, &data,
+                     FPGAMAP_SIZE_16);
+       fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
+                    FPGAMAP_SIZE_16);
 #else
-       I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
-                    | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
+       I2C_SET_REG(interrupt_status, data);
        I2C_GET_REG(interrupt_status, &val);
 #endif
 
@@ -153,26 +157,24 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
                if (len > 1)
                        val |= buffer[1] << 8;
 #ifdef CONFIG_DM_I2C
-               fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, val);
+               fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, &val,
+                             FPGAMAP_SIZE_16);
 #else
                I2C_SET_REG(write_mailbox_ext, val);
 #endif
        }
 
+       data = I2CMB_NATIVE
+              | (read ? 0 : I2CMB_WRITE)
+              | (chip << 1)
+              | ((len > 1) ? I2CMB_2BYTE : 0)
+              | (is_last ? 0 : I2CMB_HOLD_BUS);
+
 #ifdef CONFIG_DM_I2C
-       fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX,
-                       I2CMB_NATIVE
-                       | (read ? I2CMB_READ : I2CMB_WRITE)
-                       | (chip << 1)
-                       | ((len > 1) ? I2CMB_2BYTE : I2CMB_1BYTE)
-                       | (!is_last ? I2CMB_HOLD_BUS : I2CMB_DONT_HOLD_BUS));
+       fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX, &data,
+                     FPGAMAP_SIZE_16);
 #else
-       I2C_SET_REG(write_mailbox,
-                   I2CMB_NATIVE
-                   | (read ? 0 : I2CMB_WRITE)
-                   | (chip << 1)
-                   | ((len > 1) ? I2CMB_2BYTE : 0)
-                   | (is_last ? 0 : I2CMB_HOLD_BUS));
+       I2C_SET_REG(write_mailbox, data);
 #endif
 
 #ifdef CONFIG_DM_I2C
@@ -185,7 +187,8 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
        /* If we want to read, get the bytes from the mailbox */
        if (read) {
 #ifdef CONFIG_DM_I2C
-               fpgamap_read16(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val);
+               fpgamap_read(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val,
+                            FPGAMAP_SIZE_16);
 #else
                I2C_GET_REG(read_mailbox_ext, &val);
 #endif